转自:http://www.cnblogs.com/eafy/archive/2007/10/24/906792.html

1. 简介

Jetty 是一个开源的servlet容器,它为基于Java的web内容,例如JSP和servlet提供运行环境。Jetty是使用Java语言编写的,它的API以一组JAR包的形式发布。开发人员可以将

Jetty容器实例化成一个对象,可以迅速为一些独立运行(stand-alone)的Java应用提供网络和web连接。

如果让一个人说出一种开源的servlet容器,可能他们会回答Apache Tomcat。但是,Tomcat并不是孤单的,我们还有Jetty。Jetty作为可选的servlet容器只是一个额外的功能,

而它真正出名是因为它是作为一个可以嵌入到其他的Java代码中的servlet容器而设计的。这就是说,开发小组将Jetty作为一组Jar文件提供出来,因此你可以在你自己的代码中

将servlet容器实例化成一个对象并且可以操纵这个容器对象。



Jetty在servlet容器中算不上一个新面孔;它从1998年就已经崭露头角。Jetty的发布遵循了Apache 2.0的开源协议,你可以在免费软件和商业软件中使用Jetty而不用支付版税。

在本文中,笔者将为你为何需要嵌入式servlet容器提出一点见解,解释Jetty API的基础,并且展示如何使用XML配置文件来将Jetty的代码精简到最少。

本文的示例代码是在Jetty5.1.10以及Sun JDK 1.5.0_03下测试的。

2. 嵌入式Servlet容器的意义何在?

在你采用Jetty之前,理智的做法是首先问问自己:为什么自己的应用程序中需要嵌入一个servlet容器。 吸引我的视线的是Jetty可以为一个已经存在的应用程序提供servlet

功能的能力。这种能力对于很多组织都是有用的,包括Java EE应用服务器生产商,软件测试人员以及定制软件生产商。大部分的Java开发人员都可以划分到这三种情况中。

首先,考虑要建立自己的Java EE应用服务器这样一种边缘情况。根据规范,一个完整的应用服务器必须提供servlet,EJB,以及其他一些功能。你应该采用已经存在而且测试

过的组件并且使用Jetty而不是从零开始。Apache Geronimo, JBoss, 和ObjectWeb JOnAS这些项目组在建立自己Java EE应用服务器时也是这样做的。



当已经存在的容器不能满足需要的时候,软件测试人员会得益于按照需要来生成自己的servlet容器。例如,曾经有个同事想要寻找某种方式来驱动他为web service代码所写的

单元测试。对于他的这种情形——几个开发人员加上几个运行在Cruise Control中的自动单元测试——我向他示范了在他的单元测试组(unit test suites)中如何动态的(on

the fly)使用Jetty来实例化一个servlet容器。没有多余的脚本,没有剩余的文件,只有代码。



对于那些开发Java EE应用作为产品的人员来说,为什么仅仅提供一个WAR文件?这样你为会容器的规范而头疼,同时也会增加你的技术支持的成本。相反的,可以提供给客户

一个自己具有启动,停止以及管理功能的应用程序。就连硬件生产商也会从中受益:Jetty对于普通的HTTP服务(没有servlet)只需要350k的内存,这使得可以将其用在智能设

备中。你可以提供基于web的控制面板并且具有Java web应用的所有功能而不用担心那些独立的容器所带来的压力。



最后,我敢打赌嵌入式servlet容器最有趣的应用会发生在那些从来不编写传统的基于web应用的人身上。可以将Java EE和HTTP的组合作为一个C/S结构程序的后台。考虑一个

事件驱动的服务,例如(假想的)Message-Driven Bank(onjava上的另外一篇文章中提到),从main()方法启动并且等待到来的请求,就像Unix中的daemon程序一样。肯定

会有一些人想要将这个程序暴露成一种基于用户的风格,例如一个GUI桌面应用,这只是个时间问题。

要创建自己的基础组件,协议和socket通讯代码是最令人生厌的,而且会使人从业务逻辑中分心,就更不用说将来可能要调试的事情了。使用嵌入式的Jetty容器来将业务逻辑通

过HTTP协议暴露是一个不错的选择,它不用对现有程序作过多改变。选择采用Swing,SWT,XUI这些GUI并且将请求包装成HTTP Post操作,REST,甚至SOAP来完成这个

回路。与定制的特定于某个领域的协议相比,这些通用的协议可能性能稍差,但是,用不了多久,你就会从这些已经存在的经过实际检验的协议中得到好处并且节省大量的努

力。

3. 建立一个嵌入式的容器:使用Jetty API

希望以上的想法能够刺激你的胃口让你尝试一下嵌入式的servlet容器。示例程序Step1Driver 演示了一个基于Jetty的简单服务。它创建了一个servlet容器的实例,将一个servlet

class映射到一个URI,并且使用一些URL来调用这个servlet。为了代码的简洁,我牺牲了一些代码的质量。

Service对象就是Jetty容器,实例化出这样一个对象就产生了一个容器。

Server service = new Server() ;

这样一来,Service对象就像一个没有门的宾馆:没有人能够进入并且使用,所以还是没有用的。接下来的一行代码设置容器在localhost,端口7501监听。

service.addListener( "localhost:7501" ) ;



为了在所有的interface上监听,不使用主机名("addListener( ":7501" )")。就像名字暗示的那样,你可以调用addListener()多次来在多个interface上监听。

注意到示例代码中维护了Server对象的一个引用,这是将来要停止容器需要用到的。

将一个web应用映射到Service是很直观的:

service.addWebApplication(

"/someContextPath" ,

"/path/to/some.war"

) ;

这个调用将处理一个web应用中的web.xml部署描述符(descriptor)来映射其中的过滤器servlet和servlet,就像其他容器所做的那样。第一个参数是context path,这个web应

用的所有servlet和JSP都会被映射成相对于这个路径的URI。第二个参数是web应用本身。可以是一个打包的WAR文件或者目录格式的web应用。再次调用

addWebApplication()可以用来添加其他的web应用。

注意到Jetty并不需要一个完整的符合规范的WAR文件来部署servlet。如果编写了一个搭载于HTTP协议的定制应用程序协议,你可以加载一个单一的servlet并且将其通过网络提

供出去。并没有必要使用WAR文件仅仅为了使一个非web应用具有通过HTTP协议访问的功能。

为了映射这种一次性的servlet,通过在Service对象上调用getContext()动态的建立一个context。这个示例代码建立了一个叫做/embed的context。

ServletHttpContext ctx = (ServletHttpContext)

service.getContext( "/embed" ) ;

如果context不存在地话,调用getContext()将会创建一个新的context,接下来,调用addServlet()将一个servlet类映射到一个URI

ctx.addServlet(

"Simple" , // servlet name

"/TryThis/*" , // URI mapping pattern

"sample.SimpleServlet" // class name

) ;

第一个参数是该servlet的一个描述性的名字。第二个参数是要映射的路径,等同于web.xml servlet映射中的<url-pattern>。这个映射路径是相对于context path的,这里

是/embed。”/*”表示这个servlet接收/embed/TryThis这样一个URI,同时它也会接收所有以此开头的URI,例如/embed/TryThis/123。在使用一个单一的servlet来作为一个大系

统的入口的时候,这种映射方式非常有用。Struts和Axis就是实际应用中使用这样的映射方式的例子。

有时候你可能想让你的context成为root context,或者说“/”,这样更像一个普通的HTTP服务。Jetty通过Service.setRootWebapp()来支持此功能。

service.setRootWebapp(

"/path/to/another.war"

) ;

唯一的一个参数是一个web应用的路径。

容器在此时还是不活动的。而且它也没有试图去绑定要监听的socket,启动容器需要调用:

service.start() ;

这个方法会立即返回,因为Jetty将服务在一个独立的线程中运行。因此,当容器运行的时候,main()可以来做其他任何事情。

其余的代码是使用一组URL来调用这个嵌入式容器。这些调用确保容器已经在运行并且servlet按照期望的方式工作。

关闭容器就像启动它一样直观

service.stop() ;

注意最外层try/catch块中的catch语句。

{
service.start() ; // ... URL calls to mapped servlet ... service.stop() ; }catch( Throwable t ){ System.exit( 1 ) ; }

显示的调用System.exit()确保容器在发生异常的时候被关闭。否则,容器会持续运行因此整个应用程序也不会退出。

必须记住Jetty web应用并不限于使用代码来访问。如果我将service.stop()从刚才的代码中去掉,那么容器将一直运行并且我可以在浏览器中调用servlet,例如

http://localhost:7501/embed/TryThis/SomeExtraInfo

你并不一定要完全按照我说的去做。这个示例代码可以作为一个Eclipse项目运行。而且你也可以写一段shell脚本使其运行在Unix/Linux命令行中。在上面两种情况下,确信

Jetty在你的classpath中。

将配置从代码中独立出来: XML驱动的配置文件

尽管Jetty的API非常直观简练,但是直接的调用Jetty API会将大量的配置信息——端口号,context path,servlet类名——埋藏在代码之中。Jetty提供了一种基于XML的配置方式

来替代直接调用API,这样你就可以将这些配置信息都放在代码外面而使你的代码保持清洁。

Jetty的XML配置文件是基于Java反射的。java.lang.reflect中的类代表了Java中的方法和类,这样你可以实例化一个对象并且使用方法的名字和参数类型来调用它的方法。这种

情况下,Jetty的XML配置文件解析器会将XML的element和属性翻译成反射方法调用。

这段节选自Step2Driver示例类中的代码是Step1Driver的一个改良版本。要是使用到了配置文件,就必须有一定的Jetty代码来加载它。

URL serviceConfig = /* load XML file */ ;

// can use an InputStream or URL

XmlConfiguration serverFactory = new XmlConfiguration( serviceConfig ) ;

Server service = (Server) serverFactory.newInstance() ;

不可否认,这不比Step1Driver示例节省多少代码,但是,即使你要添加新的servlet或者web应用,Step2Driver的代码不会因此而增加。而直接调用Service和context对象的方法

在配置逐渐增加的情况下会越来越差。

列表1是Step2Driver加载的XML文件。顶层的<Configure> element 的属性指明了要实例化那个类。这里是Jetty Server对象。

<!-- 1 -->

<Configure class="org.mortbay.jetty.Server">

<!-- 2 -->

<Call name="addListener">

<Arg>

<!-- 3 -->
<New class="org.mortbay.http.SocketListener"> <!-- 4 -->
<Set name="Host"> <!-- 5 -->
<SystemProperty name="service.listen.host" default="localhost"/> </Set>
<Set name="Port"><SystemProperty name="service.listen.port" default="7501"/>
</Set> </New> </Arg> </Call> <Call name="getContext"> <Arg>/embed</Arg> <!--call methods on the return value of Server.getContext()--> <!-- 6 -->
<Call name="addServlet"> <!-- servlet name -->
<Arg>"Simple"</Arg> <!-- URL pattern -->
<Arg>/TryThis/*</Arg> <!-- servlet class -->
<Arg>sample.SimpleServlet</Arg> </Call> </Call>
</Configure>

<Call> element代表要在Server对象上调用的方法。这里要调用addListener(),如标记(2)处,它自己又有一个子element叫做<Arg>,这指明了方法的参数。这里我只能传递

一个字符串值作为监听的地址,而addListener()却需要接受一个SocketListener对象作为参数。因此,我要使用<New>在标记(3)处实例化一个新的SocketListener对象。标

记2和3处的代码等同于以下代码:

server.addListener(

new SocketListener( ... )

) ;
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">为了配置SocketListener自己,必须使用一个<Call>来调用它的setHost()方法,既然这个方法遵循了JavaBean的命名规则,示例代码因此使用了<Set> element(4)作为一种快</span>

捷方式。在后台,Jetty给set中name属性所指定的属性赋值,并且决定调用什么方法,这里是setHost()

setHost()的参数这里没有显示给出,而是使用了<SystemProperty>来从系统属性中来获取参数的值,这里从系统参数service.listen.host 和 service.listen.port。如果系统属性

没有定义,你可以使用default来指定一个默认值。这里,4和5等同于以下调用:

socketListener.setHost(

System.getProperty(

"service.listen.host" ,

"localhost"

)

) ;

最后注意标记6处的<Call> element位于调用getContext方法的<Call>中。内部的<Call>是作用在外部的<Call>的返回的对象上的,这里,调用的是getServlet()返回的context上

的addServlet()方法:

server.getContext().addServlet( ... ) ;
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">Jetty 小组的英明在于这个XML配置文件的进一步深入处理:我们可以注意到列表1中所有的Jetty特定的调用都是element和属性的值,而不是名字,这就意味着XML配置文件可</span>
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">以被用在任何类上,而不仅仅是Jetty的类中。根据你的应用程序的编写方式,你可以全部使用Jetty的XML配置文件来配置。</span>

4. 可执行JAR包

如果你使用Jetty的XML来配置你的应用,你需要使用大量的重复的代码来加载你的config文件并且运行你的应用。不过你可以使用Jetty的可执行的start.jar来为你加载文件,这会

让你节省更多的代码。



例如,你可以使用以下的命令行来加载Step2Driver中的Jetty服务。

CLASSPATH= ...various Jetty JARs...

java \



-Djetty.class.path=${CLASSPATH} \



-jar <jetty install path>/start.jar \



standalone.xml





注意到这个命令仅仅加载xml文件来建立容器和监听器,因此,它并不会调用示例代码中用来测试URL的代码。

5. 结论

一个嵌入式的Jetty servlet容器可以让你的web使用Java应用而不用打包成正式的web应用的形式。这提供了多种可能性,让Jetty成为你的工具箱中的一个多才多艺的帮手。

当然,我这里所写的东西并不能包含Jetty的所有内容。我建议你去访问Jetty的网站来获取更多的文档和示例代码。

什么是jetty的更多相关文章

  1. No plugin found for prefix ‘jetty’ in the current project and in the plugin groups [org.apache.maven.plugins, org.codehaus.mojo] available from the repositories

    maven配置文件(最大的那个)的<pluginGroups></pluginGroups>增加一行如下<pluginGroups><pluginGroup& ...

  2. sorl6.0+jetty+mysql搭建solr服务

    1.下载solr 官网:http://lucene.apache.org/solr/ 2.目录结构如下 3.启动solr(默认使用jetty部署) 在path路径下将 bin文件夹对应的目录加入,然后 ...

  3. 嵌入式服务器jetty,让你更快开发web

    概述 jetty是什么? jetty是轻量级的web服务器和servlet引擎. 它的最大特点是:可以很方便的作为嵌入式服务器. 它是eclipse的一个开源项目.不用怀疑,就是你常用的那个eclip ...

  4. 详解web容器 - Jetty与Tomcat孰强孰弱

    Jetty 基本架构 Jetty目前的是一个比较被看好的 Servlet 引擎,它的架构比较简单,也是一个可扩展性和非常灵活的应用服务器.它有一个基本数据模型,这个数据模型就是 Handler(处理器 ...

  5. IntelliJ IDEA使用(二):tomcat和jetty配置

    上一讲用idea创建了maven web项目,接下来我们把项目发布到tomcat和jetty运行,以便进一步地开发和调试 配置tomcat 第一.打开菜单栏 第二.点击设置按钮,添加应用服务器,选择t ...

  6. Jetty+Xfire 嵌入式webService应用实践

    1:使用场景:Mock公安网证件信息校验 2:Jetty嵌入式Server启动方式:由于Jetty9.x(需jdk7.x以上)以后Server启动方式有略微差异,所以分开说明: 2.1 Jetty9. ...

  7. 将jetty嵌入到应用中的简单案例

    前面说过jetty最广泛的应用是可以方便的嵌入到应用程序中,而不是作为应用服务器,下面就用最简单的demo来演示一个最简单的应用 1.下载并导入依赖 首先应该建立一个普通的java项目,然后把依赖包导 ...

  8. 修改jetty的默认端口号

    jetty默认端口是8080,修改端口号也很简单,首先进入到jetty服务器安装目录下会看到start.ini配置文件,这里就是jetty启动时加载的配置,其中包括要加载的模块,超时时间配置还有这里的 ...

  9. Linux下安装jetty服务器

    jetty和我们通常使用的tomcat一样,是一个开源的servlet容器,特点是轻量易部署,一方面jetty可以作为web容器使用,另一方面也是最一般的方式是jetty以一组jar包的形式发布,所以 ...

  10. Servlet引擎Jetty之入门1

    Jetty与tomcat一样,HttpWeb容器,支持实现Servlet规范. 详细介绍参考:https://www.ibm.com/developerworks/cn/java/j-lo-jetty ...

随机推荐

  1. 如何在django的filter中传递字符串变量作为查询条件(动态改变查询条件)

    一般来说在需要查询数据的时候都是以下形式 ret=Articles.objects.filter(id=1) 然而如果要动态的改变查询的条件怎么办呢? 如下代码 def getModelResult( ...

  2. CCTV评论员评论步行者与奇才的比赛

    步行者客场迎战主场作战的奇才,奇才的战士可能由于过度兴奋或是过度紧张身体僵硬,本来能打进的球都失掉了.反而,由于步行者取得了两位数的领先,越大心情越放松,打出了过去很少见的流畅局面. CCTV评论员就 ...

  3. bzoj2427: [HAOI2010]软件安装

    Description 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上,使得这些软件的价值尽可能大(即Vi的和 ...

  4. Nopcommerce 3.7 增加了Redis 作为缓存啦

    Nopcommerce 3.7  版增加了Redis 缓存,相比之前内存缓存, 感觉使用了Redis 作为缓存,明显加快了Web页面响应速度! 废话少说 拉代码: 1 git clone https: ...

  5. QT5.4 计算器程序 打包&发布,解决dll的最新解决方案

    QT写界面还是很不错,就是打包会比较麻烦,折腾了一天总算是打包完成了. QT软件的打包发布一个难点是必备dll文件的识别,现在高版本QT自带了一个windeployqt工具,直接会把需要的dll生成一 ...

  6. 修改sphinx最大输出记录数

    修改sphinx最大输出记录数 归纳如下: Sphinx的查询默认最大记录数是:1000,而我们想更改这个数值.就需要更改三个地方. 1是更改sphinx.conf配置文件的:max_matches ...

  7. 运行 Docker 容器时的安全风险:别丢了你的套接字

    我们都遇到过这种情况:你只是想尝试一段命令行,但安装进程却如同抵押贷款申请那般繁琐.如果不是强制要求完成这么多步骤,你的开发环境会被永远不会再使用的库弄乱.自然, Docker 来了以后,你惊异地发现 ...

  8. 如何解决C#编译中"csc不是内部或外部命令"的问题

    安装完 VisualStudio 2010编译环境后,是不能用命令行直接编译写好的csc文件的,如果不配置环境变量,在命令提示符(cmd)中编译扩展名为cs的文件,会出现错误提示“csc不是内部或外部 ...

  9. Windows下Redis中RedisQFork位置调整

    redis-server.exe redis.windows.conf 使用上面命令启动redis服务的时候报了以下错误信息: The Windows version of Redis allocat ...

  10. winform异型不规则界面设计

    一,不规则WINFORM窗体 Author:unknown From:Internet在以前版本的Visual Basic或Visual C++中,创建不规则窗体和控件是一件很复杂的事,不仅需要调用大 ...