jetty

一直以来,web container我主要就用tomcat。 websphere在做ibm portal的时候也接触过, 复杂的东西不太喜欢。听说resin的性能很好,下载了3.16pro试用一番,移植tomcat的应用到resin也没有碰到问题,不过eclipse的插件似乎还没有支持3.16的,所以开发用起来还有点麻烦。如果没有合法的license,启动pro版还总是会有提示说license is not valid,这就不爽了,本来还以为是完全开源免费的。看说明是pro版采用了native api 提供更好性能,我倒是更倾向于license更加开放的,于是就放弃了resin。
还有什么可以尝试呢?突然想到了jetty,jetty是原来的一位同事提到过,说他们用jetty来做开发环境的web container, 测试、正式平台才用tomcat。在javaeye论坛里面搜索jetty,看到dlee几度推荐,引起了兴趣。
这是其中一篇关于jetty的优点:
http://www.iteye.com/topic/408?page=3
dlee 写道

两点,性能极佳,配置简单方便。
主要是设计思想的不同。Tomcat 主要是作为 JSP/Servlet 最新规范的参考实现而设计,属于学院派,但是显得庞大而杂乱。Tomcat 的性能很差,一般是作为 Http Server(如 Apache)的插件来用。Jetty 主要是作为企业级产品的嵌入式组件来设计的,可以非常方便地嵌入到其它产品中。而且 Jetty 是作为单独的 Http Server 来设计的,据 Jetty 开发人员的测试,Jetty 的性能几乎与 Apache 相当。Jetty 的体系结构结构精巧紧密,JBoss、JOnAS 缺省都是把 Jetty 作为他们的 Web Container 的。Tomcat 作为 Web Container 只是可选的。
Jetty 在国内用的人不多。我们目前全部开发都是在 Jetty 上做的,感觉 Jetty 还是非常稳定可靠的。Tomcat 开发的代码只要不使用 JSP/Servlet 最新规范中的内容,移植到 Jetty 上不费吹灰之力。Jetty 也支持到 JSP 1.2/Servlet 2.3 了(还不够用吗?呵呵)。生产环境,尤其是高负载的环境中还是使用 Jetty 更好。


另外一篇关于jetty的license和性能http://www.iteye.com/topic/775?page=1
dlee 写道

说起 Jetty,没有几个人知道,而实际上由于 Jetty 的 License 非常开放,采用 Jetty 的商业产品是非常多的。Resin 据说也非常棒,但是由于 License 的原因我们不可能使用 Resin。
对 Jetty 感兴趣的朋友可以到这里看看:
http://www.mortbay.com/mortbay/powered.html
Jetty Powered
As a small, fast, embeddable web server and servlet container Jetty is used by a plethora of both commercial and open source projects.
We've listed just a few here to illustrate Jetty's versatility and the diversity of it's community. Feel free to contact us if you would like your product or project added here.
在这些使用 Jetty 的产品中不仅包括 JBoss、JOnAS 这样开源的 AppServer,还包括 WebLogic Business Connect 和 IBM Tivoli NetView 这样的商业产品。


dlee 写道

现在大家对于 Jetty 的批判全部都集中在 Jetty 的性能方面。但是对于一个产品的判断性能仅仅是一个方面,当然是一个非常重要的方面,但是也不要以偏概全。
......
我举这个例子是为了说明什么?
我仍然要说 Jetty 是一个非常好的 Web Container。因为它的设计简练而清晰(Jetty 的代码要比 Tomcat 的代码简单和清晰的多),它非常容易被嵌入到其它产品之中。它用最少的代码提供了我们常用的几乎所有 Web Container 的功能。


看完以上帖子,能对jetty有个初步认识:
1、使用简单、配置简单
2、设计模块化、代码编写简炼易懂
3、tomcat的应用移植到jetty基本不用修改
3、非常合适嵌入到其他产品,可扩展性好
5、license是完全开放的,apache2.0 license

ok,接下来看看jetty怎么用, 我也来实验一把,看到底是不是那么好。
到jetty官方的文档看看入门教程:http://docs.codehaus.org/display/JETTY/Jetty+Documentation
咋一看,内容很多,我基本上走了一圈,下意识的找嵌入式webapp的demo和怎样移植一个以前的tomcat的webapp到jetty上来,还有eclipse的jetty插件。
还好,文档里面都有的,因此我觉得也主要关注Getting Started、Tutorials、Eclipse Workbench、Configuration这四个部分就可以了。
Getting Started告诉我们启动jetty只需要:java -jar start.jar etc/jetty.xml
因此就是一句java命令,指定一个配置文件作为参数即可;
Tutorials里主要就是看Embedding Jetty
Java代码 复制代码 收藏代码
  1. Server server = new Server(8080);   
  2. Context root = new Context(server,"/",Context.SESSIONS);   
  3. root.addServlet(new ServletHolder(new HelloServlet("Ciao")), "/*");   
  4. server.start();  
Server server = new Server(8080);
Context root = new Context(server,"/",Context.SESSIONS);
root.addServlet(new ServletHolder(new HelloServlet("Ciao")), "/*");
server.start();

这样就等于配置了一个servlet mapping, 感觉是很神奇, 不过不用web.xml倒不是我想要的,我毕竟要兼顾不同web容器的兼容性。把Embedding Jetty里面的各种示例看了个遍,发现都没直接用web.xml的。
Eclipse Workbench中介绍了几个jetty for eclipse插件,试用了一下,感觉这个就不错了,简单可用:http://docs.codehaus.org/display/JETTY/Web+Tooling+Support
很多人推荐的jettylaucher反倒是没用起来, 似乎是还不支持最新的jetty6.1。
Configuration介绍了jetty.xml的配置,就是启动jetty指定的那个配置参数。
jetty自身的那些配置我倒一开始没看,一心在想怎样移植webapp到jetty这来,于是还真找到了,就在Contexts and Web Applications子章节里面有说明,分别打开Web Application Deployer  (static deploy)和 Context Deployer (hot deploy!),发现分别说的是静态部署和动态部署。静态部署就是 jetty.home/webapps/下面的应用可以启动jetty时一次都给部署,跟tomcat.home/webapps也是一样的;如果能够直接指定contextpath和webapppath就好了,动态部署估计就是我想要的了,如果仔细看一下
引用

Typically a ContextDeployer is defined in a jetty.xml file:
Xml代码 复制代码 收藏代码
  1. <Call name="addLifeCycle">  
  2.   <Arg>  
  3.     <New class="org.mortbay.jetty.deployer.ContextDeployer">  
  4.       <Set name="contexts"><Ref id="Contexts"/></Set>  
  5.       <Set name="configurationDir"><SystemProperty name="jetty.home" default="."/>/contexts</Set>  
  6.       <Set name="scanInterval">1</Set>  
  7.     </New>  
  8.   </Arg>  
  9.  </Call>  
<Call name="addLifeCycle">
  <Arg>
    <New class="org.mortbay.jetty.deployer.ContextDeployer">
      <Set name="contexts"><Ref id="Contexts"/></Set>
      <Set name="configurationDir"><SystemProperty name="jetty.home" default="."/>/contexts</Set>
      <Set name="scanInterval">1</Set>
    </New>
  </Arg>
</Call>


The ContextDeployer will scan the configurationDir directory at intervals of scanInterval seconds for xml descriptors that define contexts. Any contexts found are deployed to the passed contexts reference to a HandlerContainer (this is normally an instance of ContextHandlerCollection).

The deployment descriptors are in jetty xml format and are define and configure individual contexts. A minimal example is
Xml代码 复制代码 收藏代码
  1. <?xml version="1.0"  encoding="ISO-8859-1"?>  
  2. <!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">  
  3.  <Configure class="org.mortbay.jetty.webapp.WebAppContext">  
  4.   <Set name="contextPath">/test</Set>  
  5.   <Set name="war"><SystemProperty name="jetty.home" default="."/>/webapps/test</Set>  
  6. </Configure>  
<?xml version="1.0"  encoding="ISO-8859-1"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<Configure class="org.mortbay.jetty.webapp.WebAppContext">
  <Set name="contextPath">/test</Set>
  <Set name="war"><SystemProperty name="jetty.home" default="."/>/webapps/test</Set>
</Configure>

This example creates an instance of org.mortbay.jetty.webapp.WebAppContext and sets the contextPath to be "/test" and the resourceBase to be "$jetty.home/webapps/test". Because the context used is a standard web application context, when started it will inspect the resourceBase for a WEB-INF/web.xml for further configuration.

The ContextDeployer is added to the server as a LifeCycle. This simply means that the deployer will be started and stopped with the server. Ie when server.start() is called, then start will also be called on the deployer.

可以看出jetty.home/contexts目录下保存着动态部署的jetty.xml,在这类xml中可以设定我要的contextpath和war目录, 从上例中就可以看出部署了一个/webapps/test应用, 启动jetty之后http://localhost:8080/test就可以看到。好了,这就简单了,copy一份出来,同样放到contexts目录下,改好contextpath和war,重启jetty,移植的也能正常跑了。

当然也许觉得这样有些烦, 如果光是移植个把webapp到jetty这么干也罢了,要把jetty当作主流web开发用容器就显然不够简单。还好前面装的那个eclipse插件倒是省了不少事情,new 一个jetty server,把webapp添加到server,run即可。

好了,到这里常规方式部署一个webapp已经没问题了, 但jetty的优点和特点不是嵌入式web容器吗?我怎样在程序里面启动jetty,并把webapp给部署掉呢?
这个倒是在官方文档中我也没找到怎么做, 还是在javaeye论坛里面给找到了办法:
Java代码 复制代码 收藏代码
  1. public static void main(String[] args) throws Exception {   
  2.     Server server = new Server();   
  3.     BoundedThreadPool threadPool = new BoundedThreadPool();   
  4.     threadPool.setMaxThreads(100);   
  5.     server.setThreadPool(threadPool);   
  6.     Connector connector = new SelectChannelConnector();   
  7.     connector.setPort(8080); //端口   
  8.     server.setConnectors(new Connector[] { connector });   
  9.     WebAppContext context = new WebAppContext("你的web应用路径""你的context");   
  10.     server.addHandler(context);   
  11.     server.setStopAtShutdown(true);   
  12.     server.setSendServerVersion(true);   
  13.     server.start();   
  14.     server.join();   
  15. }  
public static void main(String[] args) throws Exception {
	Server server = new Server();
	BoundedThreadPool threadPool = new BoundedThreadPool();
	threadPool.setMaxThreads(100);
	server.setThreadPool(threadPool);
	Connector connector = new SelectChannelConnector();
	connector.setPort(8080); //端口
	server.setConnectors(new Connector[] { connector });
	WebAppContext context = new WebAppContext("你的web应用路径", "你的context");
	server.addHandler(context);
	server.setStopAtShutdown(true);
	server.setSendServerVersion(true);
	server.start();
	server.join();
}

看到了吧, 程序里面启动jetty,并发布你的应用,比较简单的吧。虽然代码是能做到,但我还是更喜欢用配置文件,怎么办?
先创建一个jetty-web.xml,就放在你的webapp目录下吧
Xml代码 复制代码 收藏代码
  1. <?xml version="1.0"?>  
  2. <!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">  
  3. <Configure id="Server" class="org.mortbay.jetty.Server">  
  4.   
  5.     <Set name="ThreadPool">  
  6.       <New class="org.mortbay.thread.QueuedThreadPool">  
  7.         <Set name="minThreads">10</Set>  
  8.         <Set name="maxThreads">200</Set>  
  9.         <Set name="lowThreads">20</Set>  
  10.         <Set name="SpawnOrShrinkAt">2</Set>  
  11.       </New>  
  12.     </Set>  
  13.   
  14.     <Call name="addConnector">  
  15.       <Arg>  
  16.           <New class="org.mortbay.jetty.nio.SelectChannelConnector">  
  17.             <Set name="host"><SystemProperty name="jetty.host" default="127.0.0.1"/></Set>  
  18.             <Set name="port"><SystemProperty name="jetty.port" default="8080"/></Set>  
  19.             <Set name="maxIdleTime">30000</Set>  
  20.             <Set name="Acceptors">2</Set>  
  21.             <Set name="statsOn">false</Set>  
  22.             <Set name="confidentialPort">8443</Set>  
  23.         <Set name="lowResourcesConnections">5000</Set>  
  24.         <Set name="lowResourcesMaxIdleTime">5000</Set>  
  25.           </New>  
  26.       </Arg>  
  27.     </Call>  
  28.   
  29.     <Set name="handler">  
  30.       <New id="Handlers" class="org.mortbay.jetty.handler.HandlerCollection">  
  31.         <Set name="handlers">  
  32.          <Array type="org.mortbay.jetty.Handler">  
  33.            <Item>  
  34.              <New id="RequestLog" class="org.mortbay.jetty.handler.RequestLogHandler"/>  
  35.            </Item>  
  36.        <Item>  
  37.            <New class="org.mortbay.jetty.webapp.WebAppContext">     
  38.               <Set name="contextPath">/demo</Set>     
  39.                           <Set name="war">xx</Set>  <!--你的web应用根目录-->  
  40.                  </New>     
  41.           </Item>  
  42.          </Array>  
  43.         </Set>  
  44.       </New>  
  45.     </Set>  
  46.        
  47.     <Ref id="RequestLog">  
  48.       <Set name="requestLog">  
  49.         <New id="RequestLogImpl" class="org.mortbay.jetty.NCSARequestLog">  
  50.           <Set name="filename"><SystemProperty name="jetty.logs"    
  51.          />/yyyy_mm_dd.request.log</Set>  
  52.           <Set name="filenameDateFormat">yyyy_MM_dd</Set>  
  53.           <Set name="retainDays">90</Set>  
  54.           <Set name="append">true</Set>  
  55.           <Set name="extended">true</Set>  
  56.           <Set name="logCookies">false</Set>  
  57.           <Set name="LogTimeZone">GMT</Set>  
  58.         </New>  
  59.       </Set>  
  60.     </Ref>  
  61.   
  62.     <Set name="stopAtShutdown">true</Set>  
  63.     <Set name="sendServerVersion">true</Set>  
  64.     <Set name="sendDateHeader">true</Set>  
  65.     <Set name="gracefulShutdown">1000</Set>  
  66.   
  67. </Configure>  
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<Configure id="Server" class="org.mortbay.jetty.Server">

    <Set name="ThreadPool">
      <New class="org.mortbay.thread.QueuedThreadPool">
        <Set name="minThreads">10</Set>
        <Set name="maxThreads">200</Set>
        <Set name="lowThreads">20</Set>
        <Set name="SpawnOrShrinkAt">2</Set>
      </New>
    </Set>

    <Call name="addConnector">
      <Arg>
          <New class="org.mortbay.jetty.nio.SelectChannelConnector">
            <Set name="host"><SystemProperty name="jetty.host" default="127.0.0.1"/></Set>
            <Set name="port"><SystemProperty name="jetty.port" default="8080"/></Set>
            <Set name="maxIdleTime">30000</Set>
            <Set name="Acceptors">2</Set>
            <Set name="statsOn">false</Set>
            <Set name="confidentialPort">8443</Set>
	    <Set name="lowResourcesConnections">5000</Set>
	    <Set name="lowResourcesMaxIdleTime">5000</Set>
          </New>
      </Arg>
    </Call>

    <Set name="handler">
      <New id="Handlers" class="org.mortbay.jetty.handler.HandlerCollection">
        <Set name="handlers">
         <Array type="org.mortbay.jetty.Handler">
           <Item>
             <New id="RequestLog" class="org.mortbay.jetty.handler.RequestLogHandler"/>
           </Item>
	   <Item>
		   <New class="org.mortbay.jetty.webapp.WebAppContext">  
			  <Set name="contextPath">/demo</Set>  
                          <Set name="war">xx</Set>  <!--你的web应用根目录-->
                 </New>  
          </Item>
         </Array>
        </Set>
      </New>
    </Set>
    
    <Ref id="RequestLog">
      <Set name="requestLog">
        <New id="RequestLogImpl" class="org.mortbay.jetty.NCSARequestLog">
          <Set name="filename"><SystemProperty name="jetty.logs" 
		 />/yyyy_mm_dd.request.log</Set>
          <Set name="filenameDateFormat">yyyy_MM_dd</Set>
          <Set name="retainDays">90</Set>
          <Set name="append">true</Set>
          <Set name="extended">true</Set>
          <Set name="logCookies">false</Set>
          <Set name="LogTimeZone">GMT</Set>
        </New>
      </Set>
    </Ref>

    <Set name="stopAtShutdown">true</Set>
    <Set name="sendServerVersion">true</Set>
    <Set name="sendDateHeader">true</Set>
    <Set name="gracefulShutdown">1000</Set>

</Configure>

以上是一个相对完整的jetty.xml,应该可以根据需要简化,重要的是加入了
Java代码 复制代码 收藏代码
  1.     
  2. <Item>   
  3. <New class="org.mortbay.jetty.webapp.WebAppContext">     
  4.     <Set name="contextPath">/demo</Set>     
  5.         <Set name="war">xx</Set>  <!--你的web应用根目录-->   
  6.  </New>     
  7.  </Item>  
 
<Item>
<New class="org.mortbay.jetty.webapp.WebAppContext">  
	<Set name="contextPath">/demo</Set>  
        <Set name="war">xx</Set>  <!--你的web应用根目录-->
 </New>  
 </Item>

一个新的handler,实现了web应用发布目录和context的指定。
这个时候,如果在程序中启动jetty,只需要:
Java代码 复制代码 收藏代码
  1. public static void main(String[] args) throws Exception {   
  2.     Server server = new Server();   
  3.     XmlConfiguration configuration = new XmlConfiguration(   
  4.     new FileInputStream(   
  5.         "xx/demo/jetty-web.xml")); //指定自定义的jetty.xml路径   
  6.     configuration.configure(server);   
  7.     server.start();   
  8. }  
public static void main(String[] args) throws Exception {
	Server server = new Server();
	XmlConfiguration configuration = new XmlConfiguration(
	new FileInputStream(
		"xx/demo/jetty-web.xml")); //指定自定义的jetty.xml路径
	configuration.configure(server);
	server.start();
}



其实连这个main函数都可不必要了,只要用org.mortbay.xml.XmlConfiguration作为启动类,Program arguments中填上自定义的jetty.xml即可。这样连eclipse插件都可以丢掉不用了。

总结:
本文作为jetty的初体验体会,着重于怎样移植webapp到jetty,以及如何快速在jetty上部署webapp,也尝试了嵌入方式启动webapp,这些工作在找到方法后很轻松(实际上我可找了很久)。主要是完成你的webapp对jetty的配置,然后start!
本文并没有重点讨论jetty.xml的配置,这部分内容可以根据官方文档和看jetty自带的examples来学习,以后有时间看了再说。

注意:
jetty6是基于servlet2.5和jsp2.1设计的,
几个核心包是jetty-6.1.11.jar、jetty-util-6.1.11.jar、servlet-api-2.5-6.1.11.jar;
如果以嵌入式启动,需要引用jsp2.1包,我一开始引用的是jsp2.0包,结果造成了一些方法调用对不上参数的问题,明显是class版本有差别,换用jsp2.1就可以了。
另外对于嵌入式,/lib/naming和/lib/plus下的包最好也全部引入。
有时候jetty配置文件中会有如下引用jetty.home等变量
<Set name="config"><SystemProperty name="jetty.home" default="."/>/etc/realm.properties</Set>
需要在启动程序配置中加上vm参数,如果是jetty.home,则加上
-Djetty.home=D:/devworkspace/jetty-6.1.11

posted @ 2011-05-30 16:10  shitou  阅读(2775)  评论(0编辑  收藏  举报