Skip to content
springside edited this page May 4, 2012 · 5 revisions

#Executable War ##Overview 看ThoughtWorks的技术雷达,里面提到了Micro-Service和Embedded Jetty。大家越来越喜欢用一个嵌入式Jetty加一个嵌入式的H2,不用依赖任何Container,就可以启动一个应用了。

这种嵌入式Embedded有两种风格:

一种是提供一个Zip包,里面有一个bin目录放着jsw(Java Service Wrapper),一个lib目录放着Jetty的jar,一个webapp目录放着真正的应用,一个conf目录放着jetty和jsw的配置文件。用户解开zip包后进入bin目录就可以简单的start/stop应用。像ActiveMQ, Solr, Nexus, Sonar等都是这个风格。

另一种更简洁,把jetty的jar包解开成class放入war包里,再放一个Main class进去,用户用java -jar xxxx.war 就可以启动应用,像Jenkins,Selenium的Server等都是这种风格。

在SpringSide的showcae项目里,演示了后一种风格,同样原理也可以自行制作第一种风格的包。

##打包 在showcase里,用mvn package -Pstandalone,就会在target目录生成一个showcase.war和一个showcase-4.xxx.standalone.war.

  1. 观察一下showcase的pom.xml,依赖的Jetty包定义成provided,既可以用来编译Main.java,又不会打包到WEB-INF/lib中. 然后定义了一个runtime级别的jstl.1.2.jar,因为Jetty用的那个Jasper的编译器只懂得从WEB-INF/lib下的jar里的META-INF中找tld,而不能从war的/META-INF中找。

  2. 然后是pom.xml里的standalone profile,可以看到是使用assembly插件实现showcase-4.xx.standalone.war的打包。

  3. 再观察assembly-standalone.xml:
    首先把org.eclipse.jetty*:* 及其依赖的包,全部解开class来, 然后打包war包里(注意要exclude掉META-INF里的内容,否则那些*.RDA之类的文件会报jar包签名错之类的错)。
    然后把原来war包里的内容同样copy到war包里。
    最后从classes中将一个Main.class也copy到war包中。

  4. 再回到pom.xml里,assembly插件还会修改war包里的META-INF/Manifest.mf,设置main class为刚才那个Main class。

最后再看一下Main.class的实现:

  System.setProperty("org.apache.jasper.compiler.disablejsr199", "true");

设置环境变量可确定使用Eclipse的JDT,而不是JDK的compiler来编译JSP。Jetty7.5后默认使用JDK Compiler,但我的机器上老是报NoJDK,郁闷死。

ProtectionDomain protectionDomain = Main.class.getProtectionDomain();
URL location = protectionDomain.getCodeSource().getLocation();
String warFile = location.toExternalForm();

神奇的语句,可以通过Main.class找到war包的路径。

String currentDir = new File(location.getPath()).getParent();
File workDir = new File(currentDir, "work");
context.setTempDirectory(workDir);

设置work dir,war包将解压到该目录,jsp编译后的文件也将放入其中。

##运行

用java -jar xxx.war -Dport=8082 可以简单的在8082端口(默认为8080)运行应用,如果要设置其他JVM参数,以及更好的基于PID关闭应用,可以编写如下script.

start.sh:

JAVA_OPT=-Xms2048m -Xmx2048m -XX:MaxPermSize=128m
java $JAVA_OPT -jar xxx.war -Dport=8082
echo $! > PID

stop.sh:

if [ -f PID ]
then
  kill `cat PID`
  rm PID
else
  echo "ERROR: PID file does not exist."
fi

返回参考手册

Clone this wiki locally