Jetty
1. Overview
Jetty作为嵌入式的Servlet服务器,用途非常广泛:
- 在开发时,我们用它在Eclipse里直接启动应用,而不是使用诸如Eclipse的Tomcat插件,先把几十兆应用打包,然后再copy到某个目录后再启动。在quickstart,showcase的测试目录里,都放着一个QuickstartServer.java,ShowcaseService.java之类的文件。
- 在功能测试时,我们用它实现容器外的测试,直接在用例里启动Jetty, 而不是先将应用打包部署到容器。在各个项目的BaseFunctionalTest中有演示。
甚至很多项目在运行期,也可以直接使用Jetty, 实现Micro-Service,详见Executable War章节。
Tomcat新版向Jetty靠了很多,比如也支持嵌入式运行,也支持集成Maven运行项目,更加分的是还实现了将自己打包成可执行war包的Maven指令。Showcase项目里也演示了通过Maven用Tomcat运行项目。
2. 改动代码后,按个回车快速重载应用
这都是被PlayFramework刺激的。 之前在Eclipse里用Main函数启动Jetty Server, 改动了代码后需要停止再启动Jetty,虽然已经免去了Tomcat插件那种重新打包几十兆的消耗,但比起php这种完全不用重启的来说还是慢,特别是关闭,启动一个新的JVM,消耗不小。
因此改动了Main函数,捕捉到回车后,重新reload context,并重新载入Class文件。感觉速度快了很多,而且不会像以前一样搞到很多个窗口。
但如果看到有class cast的错误,就还是重启一下数据库了。
while (true) {
char c = (char) System.in.read();
if (c == '\n') {
context.stop();
WebAppClassLoader classLoader = new WebAppClassLoader(context);
classLoader.addClassPath("target/classes");
classLoader.addClassPath("target/test-classes");
context.setClassLoader(classLoader);
context.start();
}
}
3. JettyFactory in SpringSide Core
JettyFactory 提供createServerInSource(int port, String contextPath)的函数,以src/main/webapp为Web应用目录创建Web Server.
函数里有三个关键的设置:
一个是JVM退出时关闭Jetty的钩子,这样子就可以在整个功能测试时启动一次Jetty,然后让它在JVM退出时自动关闭。再次鄙视Junit没有在整次测试时期的setup/teardown控制函数。
二是connector.setReuseAddress(false),在Windows下有个Windows + Sun的connector实现的问题,reuseAddress=true的话,重复启动同一个端口的Jetty不会报错。 所以必须设为false,代价是有时候上一次退出不干净,比如有TIME_WAIT时,会导致不能新的Jetty不能启动。但权衡之下还是设为False。
三同样是Windows下的问题,像javascript,css文件,会被Jetty锁住,不能修改保存,需要将webdefault.xml里的useFileMappedBuffer改为false
4.jsp taglib的tld文件不能找到的问题
这是Jetty一个很麻烦的设计,如果tld文件在当前的classloader里面就可以顺利载入,如果在parent的class loader里就会有因为安全原因而拒绝扫描,除非你像Jetty文档教的那样做了特别的设置。
在Eclipse中运行Jetty时,jetty会创建WebAppClassLoader,然后把Eclipse那个带着项目Build Path中所有Class的ClassLoader 设为parent classloader,问题就来了.....
因此SpringSide的JettyFactory封装了一个setTldJarNames(String...)的方法,供你设定包含项目中用到的tld文件的jar包,详见QuickStartServer.java中的使用。
但是还是有最悲剧的时候,比如showcase项目用了springside-core中的tld文件,而且Eclipse里sprignside-core是以项目依赖而不是jar包依赖方式存在的,这时候就完全没办法了,只好把springside-core中的tld文件copy一份到showcase的WEB-INF目录。
而在Maven运行的Jetty测试时,则需要在Surefire插件里做如下设置,原因懒得深究了。
<useSystemClassLoader>false</useSystemClassLoader>,
像Tomcat一样用Jetty
下载Jetty7 回来,解开发现bin里面居然没有windows下的bat文件,还好,自己打命令也一样
java -jar start.jar
然后把想运行的应用丢进它的webapps目录就可以了。如果要改变默认端口,命令行加上 -Djetty.port=8082 或者修改etc/jetty.xml