配色: 字号:
Jetty使用教程28—Jetty开发指南
2016-09-20 | 阅:  转:  |  分享 
  
Jetty使用教程28—Jetty开发指南

二十八、延续机制支持
28.1延续简介
延续是一种机制用来实现类似于Servlet3.0异步功能的异步Servlet,但提供了一个简单易操作的接口。

28.1.1为什么使用异步Servlets
不使用异步IO:

异步servlet的概念往往与异步IO或NIO的使用产生混淆。但是异步Servlets和异步IO还是有主要不同点:

HTTP请求通常很小并且位于一个单独的包,Servlets很少在请求时阻塞。
许多responses通常很小并且大小适合server缓冲,所以servlets通常不会再写入response时堵塞
即便我们能在servlet中使用异步IO,那也将时编程变得更加困难。例如当一个应用程序读到2到3个字节的UTF-8它会怎么做?它不得不缓冲等待更多的字节。这件事最好由容器来做而不是应用程序。
异步等待:

异步servlets的主要用法是用来等待非IO的事件或资源。许多web应用程序需要等待处理HTTP请求的各种阶段,例如:

处理请求前等待资源可用(例如:thread、JDBC连接)
在AJAXComet应用中等待一个应用程序的事件(例如:聊天消息、价格变动)
等待远程服务的一个响应(例如:RESTful、SOAP)
servletAPI(2.5之前)仅支持一种同步调用方式,所以servlet的任何等待都是阻塞式的。不幸的是,这意味着分配给请求的线程将会在等待所有资源的时候被持有:内核线程、栈存储、缓冲池、字符转换器、EE认真context等等。保存对这些资源的等待会浪费大量的系统资源。如果等待是异步进行的,那么可以进行更好的扩展和提高服务质量。

28.1.2异步Servlets例子
AJAX服务端推送

Web2.0可以使用comet技术(又叫做AJAX推送、服务端推送、长轮询)动态更新一个页面,而不需要刷新整个页面。

考虑一个股票投资的web应用程序。每个浏览器都会发一个长轮询到服务器,要求服务器提供任何用户股票价格的变动。服务器将从它所有的客户端接收到长轮询请求,并且不会立即进行响应。服务器将等待股票价格的变动,在那时它将发送一个响应到所有等待着的客户端。客户端接收到长轮询响应后会立即再次发送一个长轮询来获得未来价格的改变。

这样的话,服务器将持有每一个用户连接的长轮询,所以如果servlet不是异步的话,那么至少需要1000个线程来持有同时1000各用户。1000个线程会消耗256M资源;这些资源最好被应用所使用而不是进行无意义的等待。

如果servlet是异步的话,那么需要的线程数量将由生成相应的时间和价格变化的频率所决定。如果每个用户每10秒接收一次请求,响应需要10ms来生成,那么1000个用户仅仅需要一个线程来提供服务,256M的栈资源将被释放用于其他用途。

想获得更多关于comet的知识,可以阅读comet项目的与Jetty异步工作章节。

异步RESTfulWebService

假设一个web应用访问一个远程web服务(例如,SOAPservice或RESTfulservice),通常一个远程服务仅花几百毫秒便可产生一个响应,eBay的RESTfulweb服务通常需要350ms来匹配给定关键字的拍卖列表-虽然仅仅只有少数的10ms的CPU时间来处理本地请求和生成一个响应。

为了每秒处理1000个请求,每一个web服务调用需要200ms,那么一个web应用需要1000(200+20)/1000=220个线程和110MB内存。如果发生请求风暴时仍会导致线程不足和web服务变慢的情况。如果进行异步处理,那么web应用将不需要持有每一个线程在等待webservice响应的时候。及时异步机制需要消耗10ms(通常不消耗),那么web应用将需要1000(20+10)/1000=30个线程和15MB内存。这将有86%的性能提升,和95MB的内存释放可用于其他地方。而且,如果多重webservices请求需要,异步调用将允许并行调用,而不是顺序调用,不需要额外分配线程。

这有一个Jetty的异步解决方案,查看例子。

服务质量(例如,JDBC连接池)

假设一个web应用每秒处理400个应用请求,每个请求需要与数据库交互50ms。为了处理这些请求,平均每秒需要40050/1000=20个JDBC连接。然而请求经常爆发或者延迟。为了保护访问风暴下的数据库,通常使用数据库连接池来限制连接。所以对于这个应用程序,它将是合理应用JDBC30连接池,提供50%的额外保证。

如果请求在某一时刻翻倍,那么30个连接将不能每秒处理600个请求,那么每秒200个请求将要等待连接池分配连接。如果一个servlet容器有一个200个线程的线程池,那么所有的线程将要等待连接池1秒钟。1秒过后,web应用将不能处理任何请求,因为所有的线程都不可用,即便请求不是用数据库。加倍线程池数量需要额外的100MB内存,而只会给应用程序另外1mc的负载恩典。

这个线程饥饿状况也会发生如果数据库运行缓慢或暂时不可用。线程饥饿是频发的问题,并导致整个web服务来锁定和变得反应迟钝。如果web容器能够不使用线程来暂停等待一个JDBC连接请求,那么线程饥饿就不会发生,因为只有30个线程被用来访问数据库,而其他470个线程用于处理请求,不访问数据库。

Jetty的解决方案的一个示例,请参阅Server过滤器的质量。

28.1.3Servlet线程模型
Javaservlet的可伸缩性能的主要原因是由服务线程模型引起:

每连接一个线程

传统的JavaIO模型,每个TCP/IP连接与一个线程关联。如果你有一些非常活跃的线程,那么这个模型可以扩展到非常高的每秒请求数。

然而,许多web应用程序的典型特性是许多持久的HTTP连接等待用户阅读完网页,或者搜索下一个点击的连接。这样的配置,thread-per-connection模型将会有成千的线程需要支持成千的用户的大规模部署问题。

每请求一个线程

JavaNIO库支持异步IO,这样线程就不需要分配到每个连接上,当连接闲置时(两次请求中间),那么连接将会添加到NIO选择集合,它允许一个线程扫描许多活动连接。只有当IO被检测到输入输出的时候线程才会被分配给它。然而servlet2.5API模型仍然需要将一个线程分配给一个请求持用的所有时间内。

这种thread-per-request模型允许更大比例的连接(用户)由于更少的调度延时导致的每秒请求数的减少。

异步请求处理

Jetty的支持连接API(和servlet3.0异步)在servletAPI引入一种改变,就是允许将一个请求多次分配到一个servlet。如果这个servlet没有所需的资源,那么这个servlet将被挂起(或将它放入异步模型),那么这个servlet将会没有任何响应的被返回。当等待的资源可用时,请求将会重新分配到这个servlet,使用一个新的线程,一个响应就会产生。

28.2使用延续
异步servlet最初是由Jetty的延续机制引进来的,这是Jetty的一个特殊的机制。Jetty7以后,延续的API已经被扩展成一个通用的API,将在任何servlet-3.0容器上进行异步工作,Jetty6,7,8同样支持。延续机制还可以在servlet2.5容器下以阻塞方式运行。

28.2.1获得一个延续
ContinuationSupport工厂可以通过request来获得一个延续实例:

Continuationcontinuation=ContinuationSupport.getContinuation(request);
28.2.2挂起一个请求
为了挂起一个请求,挂起方法可以在延续上被调用:

复制代码
voiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)
{
...
//可选择的:
//continuation.setTimeout(long);
continuation.suspend();
...
}
复制代码
请求的生命周期将会从Servlet.service(...)和Filter.doFilter(...)的调用延续到容器的返回。当这些调用方法返回时,挂起的请求将不会被提交响应也不会被发送到客户端。

一旦请求被挂起,延续将会注册一个异步服务,这样等待的事件发生时异步服务将会被调用。

请求将会被挂起,直到continuation.resume()或continuation.complete()方法被调用。如果两个都没有被调用那么延续将会被超时。超时应该设置在挂起之前,通过continuation.setTimeout(long)这个方法,如果没有被设置,那么将使用默认的时间。如果没有超时监听着挂起延续,或者完成这个延续,那么调用continuation.isExpired()返回true。

挂起类似于servlet3.0的request.startAsync()方法。不像jetty6的延续,异常不会被抛出并且方法会正常返回。这允许注册的延续在挂起后发生避免发生互斥。如果一个需要一个异常(不知道延续而绕过代码并试图提交响应),那么continuation.undispatch()方法将会被调用退出当前线程,并抛出一个ContinuationThrowable异常。

28.2.3恢复一个请求
一旦异步事件发生,那么延续将被恢复:

voidmyAsyncCallback(Objectresults)
{
continuation.setAttribute("results",results);
continuation.resume();
}
当延续被恢复,请求会被重新分配到这个servlet容器,就像请求重新来过一样。然而在重新分配过程中,continuation.isInitial()方法返回false,所有设置到异步处理器上的参数都是有效的。

延续的恢复类似于Servlet3.0的AsyncContext.dispatch()方法。

28.2.4完成一个请求
当重新恢复一个请求时,异步处理器可能会生成响应,在写入响应后,处理器必须显示的通过调用方法表明延续完成了。

voidmyAsyncCallback(Objectresults)
{
writeResults(continuation.getServletResponse(),results);
continuation.complete();
}
当完成方法被调用,容器会安排响应提交并刷新。延续的完成类似于Servlet3.0的AsyncContext.complete()。

28.2.5延续的监听
一个应用有可能通过ContinuationListener监听延续的各个状态。

复制代码
voiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)
{
...

Continuationcontinuation=ContinuationSupport.getContinuation(request);
continuation.addContinuationListener(newContinuationListener()
{
publicvoidonTimeout(Continuationcontinuation){...}
publicvoidonComplete(Continuationcontinuation){...}
});

continuation.suspend();
...
}
复制代码
延续的监听类似于Servlet3.0的AsyncListeners。

28.3常用延续模式
28.3.1暂停恢复模式
暂停/恢复模式用在当一个servlet或一个filter用来产生一个响应,在被异步处理器中断并恢复后。一般请求的属性用来传递结果,用来表明请求已经被暂停。

复制代码
voiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)
{
//如果我们需要获得异步的结果
Objectresults=request.getAttribute("results");
if(results==null)
{
finalContinuationcontinuation=ContinuationSupport.getContinuation(request);

//如果没有超时
if(continuation.isExpired())
{
sendMyTimeoutResponse(response);
return;
}

//恢复request
continuation.suspend();//注册前一直被暂停

//被异步服务注册,此处的代码将被服务调用
myAsyncHandler.register(newMyHandler()
{
publicvoidonMyEvent(Objectresult)
{
continuation.setAttribute("results",results);
continuation.resume();
}
});
return;//或者continuation.undispatch();
}

//发送结果
sendMyResultResponse(response,results);
}
复制代码
这是一个非常好的模式即当响应需要servlet容器的工具(如,使用了一个web框架)或者一个事件将恢复多个请求导致容器的线程池被多个处理器使用。

28.3.2暂停继续模式
暂停/完成模式是用来当一个异步处理器被用来生成一个响应的情况:

复制代码
voiddoGet(HttpServletRequestrequest,HttpServletResponseresponse)
{
finalContinuationcontinuation=ContinuationSupport.getContinuation(request);

//如果没有超时
if(continuation.isExpired())
{
sendMyTimeoutResponse(request,response);
return;
}

//将请求挂起
continuation.suspend();//response可能被包装

//r注册给异步服务,代码将被服务调用
myAsyncHandler.register(newMyHandler()
{
publicvoidonMyEvent(Objectresult)
{
sendMyResultResponse(continuation.getServletResponse(),results);
continuation.complete();
}
});
}
复制代码
这种模式在以下这种情况下是非常好的,即响应不需要容器的工具(如使用一种web框架)并且事件将会恢复一次延续。如果多个响应将被发送(例如,聊天室),那么写一次响应将会阻塞并在其他响应上导致一个DOS。

28.3.3示例
ViewCode
这个ChatServlet例子,展示了挂起/恢复模式被用来建立一个聊天室(使用了异步servlet)。相同的原则将应用于cometd这样的框架,为这样的应用提供一个基于延续的丰富的环境。

ViewCode
这个QoSFilter(这是jetty-servlets包中的一个类的),在过滤器内限制请求数量并使用挂起/恢复风格。这个可以用来保护JDBC连接池,或者限制对其他有限资源的访问。

这个DosFilter(这是jetty-servlets包中的一个类的,源码不再贴出)例子和QoSFilter比较相似,但是以拒绝服务攻击的方式来保护web应用,尽可能从应用程序内进行保护。

如果检测到同一个源的大量请求,那么这些请求将会被挂起并生成一个警告。这假设攻击者使用简单的阻塞方式来攻击,所以暂停你想保护的他们想访问的资源。真正有效避免DOS攻击应该交于网络设备。

ViewCode
这个ProxyServlet(这是jetty-proxy包中的一个类的)例子使用挂起/完成模式,Jetty异步客户端实现一个可扩展的代理服务器。

二十九、框架
29.1Spring设置
你可以在代码中组装和配置Jetty或者完全使用Spring的IOC框架。如果你想做的仅仅是将你的Jetty服务嵌入到Spring中,那么可以简单的看下面例子的xml片段。如果你想使用spring来替换jetty-xml用于启动一个普通的Jetty应用,你可以这么做但是将不会依赖其他的系统框架。

29.1.1Jetty-Spring模块
Jettyspring模块的功能是可以通过该模块启动Jetty。例如:

$java-jarstart.jar--add-to-startd=spring
这(或者使用--add-to-start=spring命令)将创建一个${jetty.home}/lib/spring目录,并将jetty-spring的jar包放入其中。但是不提供spring的jar包及其依赖包。你需要自己下载它们并将它们放到Jetty的classpath下-你可以使用由spring.mod创建的${jetty.home}/lib/spring目录存放这些jar。

29.1.2使用Spring配置Jetty
通过spring配置Jetty是非常简单的通过调用springAPIs将其作为一个bean。下面是一个例子模仿默认jetty启动配置。

复制代码






















































复制代码
29.2OSGI
29.2.1简介
JettyOSGi基础设施提供了一个内置有OSGi容器的Jetty容器内。传统的JavaEEweb应用可以被部署,除此之外还有Jetty的与OSGi一起的ContextHandlers。此外,基础设施还支持OSGiHttpService接口。

29.2.2常规设置
所有的Jettyjar包含清单条目确保他们可以部署为一个OSGi容器包。您将需要安装一些jettyjar到OSGi容器中。你总是可以在maven仓库中获得Jetty的jar包,或者你可以在下载的Jetty软件包中获取。这里有一个Jettyjar包的最小集合:

Jar 包名称
jetty-util

org.eclipse.jetty.util

jetty-http

org.eclipse.jetty.http

jetty-io

org.eclipse.jetty.io

jetty-security

org.eclipse.jetty.security

jetty-server

org.eclipse.jetty.server

jetty-servlet

org.eclipse.jetty.servlet

jetty-webapp

org.eclipse.jetty.webapp

jetty-deploy

org.eclipse.jetty.deploy

jetty-xml

org.eclipse.jetty.xml

jetty-osgi-servlet-api

org.eclipse.jetty.toolchain



+提示
我们建议在部署的时候同时添加annotation-relatedjar包,因为越来越多的Servlet使用注解来完成它们的功能。

你也同样会需要OSGi事件管理服务和OSGi配置管理服务。如果你的OSGi容器没有自动将这些服务启用,那么你需要以适当的方式将它们添加到容器中。

29.2.3JettyOSGi容器
29.2.3.1jetty-osgi-bootjar
现在你已经安装好Jetty最基本的jar包,那么你需要继续安装jetty-osgi-boot.jar包,在Maven仓库中下载,点击我(http://central.maven.org/maven2/org/eclipse/jetty/osgi/jetty-osgi-boot/)。

当它启动时,这个包将会实例化并在Jetty的OSGi容器可用。如果这个包没有自动安装到OSGi容器中,那么你应该使用命令手动将其安装到容器的中。

29.2.3.2定制Jetty容器
在安装之前,你可能希望定制一下Jetty容器。通常这应该由一些系统属性个组合和通常的jettyxml配置文件来完成。定义系统属性的方式依赖于您使用OSGi容器,所以确保你熟悉如何设置您的环境。在下面的例子中,我们将假定OSGi容器允许我们将系统属性设置为简单的名称=值对。

可用的系统属性有:

jetty.http.port

如果没有特别指定,默认8080。

jetty.home

这个属性或者jetty.home.bundle必须被指定。这个属性应该指向包含配置xml文件的一个文件系统位置。例如:

jetty.home=/opt/custom/jetty

/opt/custom/jetty文件夹包含:

etc/jetty.xml
etc/jetty-selector.xml
etc/jetty-deployer.xml
etc/jetty-special.xml

jetty.home.bundle

这个属性或jetty.home属性必须被配置。这个属性应该指定一个包含jettyhome/文件夹的包名。jettyhome/文件夹必须有一个名为etc/(包含启动的xml配置文件)的子文件夹。jetty-osgi-boot.jar里面包含jettyhome/文件夹,并有默认的xml配置文件。下面展示如何指定它:

jetty.home.bundle=org.eclipse.jetty.osgi.boot

这个jar包,有如下配置文件:

META-INF/MANIFEST.MF
jettyhome/etc/jetty.xml
jettyhome/etc/jetty-deployer.xml
jettyhome/etc/jetty-http.xml

jetty.etc.config.urls

这个属性指定xml文件的路径。如果没有指定则默认为:

etc/jetty.xml,etc/jetty-http.xml,etc/jetty-deployer.xml

29.2.3.3将Jetty容器做为OSGi一个服务
现在你可以将jetty-osgi-boot.jar部署到你的OSGi容器中了。一个Jetty的server实例将会被创建,xml配置文件的配置将会应用在上面,然后它将做为一个OSGi服务发布。通常,你不需要与服务的实例进行交互,然而你仍然可以通过使用OSGiAPI的引用来获得Jetty。

org.osgi.framework.BundleContextbc;
org.osgi.framework.ServiceReferenceref=bc.getServiceReference("org.eclipse.jetty.server.Server");

Server服务有一些与之相关的属性,你可以通过org.osgi.framework.ServiceReference.getProperty(String)方法来获得:

managedServerName

由jetty-osgi-boot.jar创建的Jetty实例,被称为“默认Jetty服务”

jetty.etc.config.urls

在jetty.home或jetty.home.bundle/jettyhome下的xml配置url列表

29.2.3.4新增更多的Jetty服务
正如我们在前面章节中所看到的,jetty-osgi-boot的代码将会通过jetty.etc.config.urls指定的xml配置文件创建一个org.eclipse.jetty.server.Server实例,然后将其注册为一个OSGi服务。默认实例的默认名称为“defaultJettyServer”

你也可以创建另外的应用实例,然后注册为OSGi服务,jetty-osgi-boot代码会发现它们,然后配置它们,这样它们就可以部署ContextHandlers和webapp包。当你部署webapps或者ContextHandlers做为一个包或者一个服务(看下面的章节),你可以通过服务器的名称针对他们被部署到一个特定的服务器实例。

这里有一个例子说明如何创建一个新的server实例并且注册到OSGi这样jetty-osgi-boot代码会发现它、配置它,这样它就可以部署目标:

复制代码
publicclassActivatorimplementsBundleActivator{

publicvoidstart(BundleContextcontext)throwsException{

Serverserver=newServer();
//在这里对服务进行任何配置
StringserverName="fooServer";
DictionaryserverProps=newHashtable();
//为当前服务定义一个唯一的服务名
serverProps.put("managedServerName",serverName);
//为当前服务设置一个唯一的端口
serverProps.put("jetty.http.port","9999");
//让Jetty应用一些配置文件到这个实例上
serverProps.put("jetty.etc.config.urls",
"file:/opt/jetty/etc/jetty.xml,file:/opt/jetty/etc/jetty-selector.xml,file:/opt/jetty/etc/jetty-deployer.xml");
//做为一个OSGi服务,使之被发现
context.registerService(Server.class.getName(),server,serverProps);

}
}
复制代码
现在我们可以创建一个名为"fooServer"的服务,我们可以部署这个webapps和ContextHandlers做为一个包或者服务。这里有一个例子关于部署一个webapp做为一个服务并且将其定位到上面创建的"fooServer"服务:

复制代码
publicclassActivatorimplementsBundleActivator{

publicvoidstart(BundleContextcontext)throwsException{

//创建一个webapp并指向"fooServer
WebAppContextwebapp=newWebAppContext();
Dictionaryprops=newHashtable();
props.put("war",".");
props.put("contextPath","/acme");
props.put("managedServerName","fooServer");
context.registerService(ContextHandler.class.getName(),webapp,props);
}
}
复制代码
29.2.4作为Webapps部署Bundles
29.2.4.1部署规则
OSGi容器监听已经安装的Bundles,并将其部署到已有的webapp上。

任何符合下面条件的将会做为webapp进行部署:

包含一个WEB-INF/web.xml文件的Bundle

如果一个bundle包含一个web应用描述,那么它将会被自动部署。这是一个简单的方法来部署经典JavaEEwebapps。Bundle的MANIFEST包含Jetty-WarFolderPath(之前的版本为jetty-9.3)或Jetty-WarResourcePath,这是bundle里面关于webapp资源的位置。通常这是有用的尤其当bundle不是一个纯粹的webapp,而是bundle的一个组件的时候。这里有一个webapp资源的路径不是bundle根路径的例子,而是在web/MANIFEST文件中:

Bundle-Name:Web
Jetty-WarResourcePath:web
Import-Package:javax.servlet;version="3.1",
javax.servlet.resources;version="3.1"
Bundle-SymbolicName:com.acme.sample.web

Bundle包含:

META-INF/MANIFEST.MF
web/index.html
web/foo.html
web/WEB-INF/web.xml
com/acme/sample/web/MyStuff.class
com/acme/sample/web/MyOtherStuff.class

BundleMANIFEST文件包含Web-ContextPath属性

这个头是在OSGi中使用webapp的RFC-66规范的一部分。这里有一个基于前面的例子,使用Web-ContextPath头来设置部署contextpath为/sample。MANIFEST如下:

Bundle-Name:Web
Jetty-WarResourcePath:web
Web-ContextPath:/sample
Import-Package:javax.servlet;version="3.1",
javax.servlet.resources;version="3.1"
Bundle-SymbolicName:com.acme.sample.web

你也可以在你的bundle的MANIFEST中定义额外的头信息用来帮助应用程序部署:

Jetty-defaultWebXmlFilePath

用来部署webapp的webdefault.xml的路径。这个路径可以是绝对路径(绝对路径或file:url)或者相对路径(相对于bundle根路径)。默认的webdefault.xml文件将后安装到OSGi容器中。

Jetty-WebXmlFilePath

web.xml文件的地址。这个路径可以是绝对路径(绝对路径或file:url)或者相对路径(相对于bundle根路径)。默认为WEB-INF/web.xml。

Jetty-extraClassPath

新增到webapp的类加载器中额外的类路径。

Jetty-bundleInstall

基础文件夹的路径用来覆盖已经安装的bundled-主要用于那些默认方式解压的OSGi框架。

Require-TldBundle

webapp依赖的所有包含TLD的bundle,以逗号分割的列表。

managedServerName

部署webappbundle的服务实例名。如果没有指定,那么默认为"defaultJettyServer"。

Jetty-WarFragmentResourcePath

包含webapp静态资源的在web-bundle中的路径。这些路径将会追加到webapp的基础资源路径下。

Jetty-WarPrependFragmentResourcePath

包含webapp静态资源的在web-bundle中的路径。这些路径将会追加到webapp的基础资源路径下。

Jetty-ContextFilePath

将要部署到webapp中的bundle路径列表。或者可能包含一个单独的Jettycontext文件叫做"jetty-webapp-context.xml",在webapp的bundle的META-INF文件夹下,它将会自动部署到webapp中。

29.2.4.2为webappbundle定义上下文路径
正如我们所看到的在前面的小节中,如果一个bundled的MANIFEST文件包含RFC-66规范的头属性Web-ContextPath,那么Jetty将会使用这个做为上下文路径。如果MANIFEST文件中没有这个头信息,那么Jetty将会根据最后一个bundle元素的地址(通过Bundle.getLocation()方法,并去掉扩展名)编造一个上下文路径。

例如,我们有一个bundle,路径如下:

file://some/where/over/the/rainbow/oz.war

那么生成的上下文路径将是:

/oz

29.2.4.3用于webappbundles的额外属性
你可以通过Jetty的xml文件来进一步定制你的webapp。这些xml文件必须放置在bundle的META-INF下面,而且名称必须为jetty-webapp-context.xml。

这里有一个webappbundle例子,包含如下文件:

META-INF/MANIFEST.MF
META-INF/jetty-webapp-context.xml
web/index.html
web/foo.html
web/WEB-INF/web.xml
com/acme/sample/web/MyStuff.class
com/acme/sample/web/MyOtherStuff.class

这里还有一个META-INF/jetty-webapp-context.xml文件的例子:

复制代码





META-INF/webdefault.xml

复制代码
正如你所看到的,这是一个普通的上下文xml文件,用来设置webapp。然而,有一些额外的有用的属性,可以引用:

Server

这是一个Jettyorg.eclipse.jetty.server的引用。在这个contextxml文件配置的Server实例将会被部署。

bundle.root

这是一个org.eclipse.jetty.util.resource.Resource的引用,用来代表Bundle路径。这个可以是一个文件系统的文件夹,或者是一个jar文件的地址。

29.2.5部署Bundles做为JettyContextHandlers
29.2.5.1基本部署
为了部署一个webapps,JettyOSGi容器监听所有安装的bundle,不使用重量级的webapp而是使用灵活的ContextHandlers概念的Jetty-specific。

根据下面的标准来决定是否部署为一个ContextHandler:

Bundel的MANIFEST包含Jetty-ContextFilePath属性

一系列context文件的名字-每一个代表一个ContextHandler都将会部署到Jetty。context文件可以在bundle里面,也可以在文件系统的任何位置,或者在jetty.home文件夹下。一个在bundle里面的context文件的配置:

Jetty-ContextFilePath:./a/b/c/d/foo.xml

一个在文件系统的context文件配置:

Jetty-ContextFilePath:/opt/app/contexts/foo.xml

一个相对于jetty.home路径的context文件配置:

Jetty-ContextFilePath:contexts/foo.xml

多个不同的context文件配置:

Jetty-ContextFilePath:./a/b/c/d/foo.xml,/opt/app/contexts/foo.xml,contexts/foo.xml

其它可用来配置部署ContextHandler的属性有:

managedServerName

用来部署webappbundle的Server实例的名称。如果没有特别指定,默认的名称为"defaultJettyServer"。

29.2.5.2为ContextHandlerBundle确定上下文路径
通常ContextHandler的上下文路径在context的xml文件中进行配置。然而你仍然可以通过使用MANIFEST文件中的Web-ContextPath属性进行覆盖。

29.2.5.3额外的contextxml文件可用属性
在JettyOSGi容器将发现于MANIFEST文件头信息应用于contextxml文件中之前,可以在文件中设置一些有用的属性:

Server

这是一个Jettyorg.eclipse.jetty.server的引用。在这个contextxml文件配置的Server实例将会被部署。

bundle.root

这是一个org.eclipse.jetty.util.resource.Resource的引用,用来代表Bundle路径。这个可以是一个文件系统的文件夹,或者是一个jar文件的地址。

这里有一个contextxml文件的例子,应用了这些属性:

复制代码












/static/



/unset










index.html


max-age=3600,public




复制代码
29.2.6部署服务做为webapp
为了部署而去监听MANIFEST文件中定义的webapp或ContextHandler,JettyOSGi容器也会监听已经注册的是org.eclipse.jetty.webapp.WebAppContext实例的OSGi服务。所以你可以编程创建一个WebAppContext,把它注册为一个服务,然后让Jetty发现并部署它。

这里有一个例子,部署了一个静态资源包,是一个org.osgi.framework.BundleActivator实例的WebAppContext:

包中的资源有:

META-INF/MANIFEST.MF
index.html
com/acme/osgi/Activator.class

MANIFEST.MF文件的内容为:

Bundle-Classpath:.
Bundle-Name:JettyOSGiTestWebApp
DynamicImport-Package:org.eclipse.jetty.;version="[9.0,10.0)"
Bundle-Activator:com.acme.osgi.Activator
Import-Package:org.eclipse.jetty.server.handler;version="[9.0,10)",
org.eclipse.jetty.webapp;version="[9.0,10)",
org.osgi.framework;version="[1.5,2)",
org.osgi.service.cm;version="1.2.0",
org.osgi.service.packageadmin;version="[1.2,2)",
org.osgi.service.startlevel;version="1.0.0",
org.osgi.service.url;version="1.0.0",
org.osgi.util.tracker;version="1.3.0",
org.xml.sax,org.xml.sax.helpers
Bundle-SymbolicName:com.acme.testwebapp

主要的代码为:

复制代码
publicvoidstart(BundleContextcontext)throwsException
{
WebAppContextwebapp=newWebAppContext();
Dictionaryprops=newHashtable();
props.put("Jetty-WarResourcePath",".");
props.put("contextPath","/acme");
context.registerService(ContextHandler.class.getName(),webapp,props);
}
复制代码


上面的安装信息足够Jetty来识别并部署一个WebAppContext到/acme下。

就像上面的例子展示的那样,你可以使用OSGi服务属性来对Jetty进行额外的配置:

Jetty-WarFolderPath(9.3及以后版本)或者Jetty-WarResourcePath::webapp静态资源root根目录。
Web-ContextPath::部署webapp的路径。
Jetty-defaultWebXmlFilePath::部署webapp包的webdefault.xml文件的路径。默认在OSGi容器内。
Jetty-WebXmlFilePath::web.xml的路径,默认为WEB-INF/web.xml。
Jetty-extraClassPath::增加到webapp当前的类加载的类路径。
Jetty-bundleInstall::用于覆盖安装包的基文件夹-常用于没有打包的OSGi框架。
Require-TldBundle::额外的包含TLD的包。
managedServerName::部署webappbundle的服务实例名。如果没有指定,那么默认为"defaultJettyServer"。
Jetty-WarFragmentResourcePath::包含webapp静态资源的在web-bundle中的路径。这些路径将会追加到webapp的基础资源路径下。
Jetty-WarPrependFragmentResourcePath::将要部署到webapp中的bundle路径列表。或者可能包含一个单独的Jettycontext文件叫做"jetty-webapp-context.xml",在webapp的bundle的META-INF文件夹下,它将会自动部署到webapp中。
29.2.7部署服务做为JettyContextHandlers
同部署WebAppContexts相似,Jetty的OSGi容器可以侦测注册的ContextHandler的OSGi服务并确保它们被部署。ContextHandler可以在注册为一个OSGi服务前被完全配置好-在这种情况下,Jetty的OSGi容器仅仅部署它-或者ContextHandler可以配特别的配置,这种情况下Jetty的OSGi容器完全通过context的xml配置文件或者属性文件来配置。

这里有一个例子部署一个org.osgi.framework.BundleActivator实例的静态资源包,并注册为OSGi服务,传递定义在context的xml配置文件中的属性用于部署:

包内容如下:

META-INF/MANIFEST.MF
static/index.html
acme.xml
com/acme/osgi/Activator.class
com/acme/osgi/Activator$1.class

MANIFEST.MF文件内容如下:

Bundle-Classpath:.
Bundle-Name:JettyOSGiTestContext
DynamicImport-Package:org.eclipse.jetty.;version="[9.0,10.0)"
Bundle-Activator:com.acme.osgi.Activator
Import-Package:javax.servlet;version="2.6.0",
javax.servlet.resources;version="2.6.0",
org.eclipse.jetty.server.handler;version="[9.0,10)",
org.osgi.framework;version="[1.5,2)",
org.osgi.service.cm;version="1.2.0",
org.osgi.service.packageadmin;version="[1.2,2)",
org.osgi.service.startlevel;version="1.0.0.o",
org.osgi.service.url;version="1.0.0",
org.osgi.util.tracker;version="1.3.0",
org.xml.sax,org.xml.sax.helpers
Bundle-SymbolicName:com.acme.testcontext

主要的代码:

复制代码
publicvoidstart(finalBundleContextcontext)throwsException
{
ContextHandlerch=newContextHandler();
ch.addEventListener(newServletContextListener(){

@Override
publicvoidcontextInitialized(ServletContextEventsce)
{
System.err.println("Contextisinitialized");
}

@Override
publicvoidcontextDestroyed(ServletContextEventsce)
{
System.err.println("Contextisdestroyed!");
}

});
Dictionaryprops=newHashtable();
props.put("Web-ContextPath","/acme");
props.put("Jetty-ContextFilePath","acme.xml");
context.registerService(ContextHandler.class.getName(),ch,props);
}
复制代码
acme.xml配置文件的内容:

复制代码












/static/



/unset










index.html


max-age=3600,public




复制代码
你也可以使用如下的OSGi服务的属性:

managedServerName

部署的webapp的Server实例的名称。如果没有指定,默认的Server实例名称为"defaultJettyServer"。

额外的可配置的在context文件的属性

在Jetty的OSGi容器应用一个在Jetty-ContextFilePath属性下发现的context的xml文件时,它可以设置一些有用的属性在xml文件中:

Server

这个引用Jettyorg.eclipse.jetty.server.Server实例,及即将应用context的xml文件部署的ContextHandler。

bundle.root

这个引用org.eclipse.jetty.util.resource.Resource实例,代表着做为一个服务部署ContextHandler包的路径(通过Bundle.getLocation()来获得)。这个可以是一个在文件系统的文件夹如果OSGi容器可以自动解压包文件,或者是一个jar包路径,如果包文件不被解压。

在上面的例子中你可以看到这两个属性同时应用的场景在context的xml文件中。

29.2.8对于OSGi服务平台的企业规范支持
JettyOSGi容器对于WebAppContexts和ContextHandlers实现企业规范v4.2,在前面的章节已介绍通过包或者OSGi服务的形式进行部署。

Context属性

对于每一个WebAppContext或ContextHandler,下面的属性是必须的:

osgi-bundleContext:此属性的值是代表与WebAppContext或ContextHandler关联的代表包的BundleContext。
Service属性

规范要求,每一个被JettyOSGi容器部署的WebAppContext或ContextHandler,同时必须发布为OSGi服务(除非它已经是一个OSGi服务),下面的属性与服务有关:

osgi.web.symbolicname:与WebAppContext或ContextHandler关联的包的符号名称
osgi.web.version:与WebAppContext或ContextHandler关联的包的版本
osgi.web.contextpath:WebAppContext或ContextHandler的context路径
OSGi事件

根据规范要求,下面的事件需要被公布:

org/osgi/service/web/DEPLOYING:JettyOSGi容器部署一个WebAppContext或者ContextHandler
org/osgi/service/web/DEPLOYED:已经完成部署并成为一个service
org/osgi/service/web/UNDEPLOYING:JettyOSGi容器卸载一个WebAppContext或者ContextHandler
org/osgi/service/web/UNDEPLOYED:JettyOSGi容器卸载完成一个WebAppContext或者ContextHandler,已不再是一个service
org/osgi/service/web/FAILED:JettyOSGi容器部署一个WebAppContext或者ContextHandler失败
29.2.9JSP的使用
29.2.9.1安装
为了在你的webapp和应用包中使用JSP,你需要按照JSP和JSTL的jar包和它们的依赖包到你的OSGi容器中。一些你可以在Jetty程序包中发现,当然也有些需要从Maven仓库中下载。这里有一个需要的jar包的列表。

Table29.2.JSP需要的jar包

Jar包 包名 路径
Theannotationjars


org.mortbay.jasper:apache-el

org.mortbay.jasper.apache-el

Distributionlib/apache-jsp

org.mortbay.jasper:apache-jsp

org.mortbay.jasper.apache-jsp

Distributionlib/apache-jsp

org.eclipse.jetty:apache-jsp

org.eclipse.jetty.apache-jsp

Distributionlib/apache-jsp

org.eclipse.jdt.core-3.8.2.v20130121.jar

org.eclipse.jdt.core.compiler.batch

Distributionlib/apache-jsp

org.eclipse.jetty.osgi:jetty-osgi-boot-jsp

org.eclipse.jetty.osgi.boot.jsp

Mavencentral

对于JSTL库,我们建议使用Glassfish的实现,它有一些简单的依赖如下:

Table29.3.GlassfishJSTL需要的jar包

Jar包 包名 路径
Thejspjars


org.eclipse.jetty.orbit:javax.servlet.jsp.jstl-1.2.0.v201105211821.jar

javax.servlet.jsp.jstl

Distributionlib/jsp

org.glassfish.web:javax.servlet.jsp.jstl-1.2.2.jar

org.glassfish.web.javax.servlet.jsp.jstl

Distributionlib/jsp

当然,你也可以使用Apache的JSTL实现,当然也需要一些依赖:

Table29.4.ApacheJSTL需要的jar包

Jar包 包名 路径
Thejspjars


org.apache.taglibs:taglibs-standard-spec:jar:1.2.1

org.apache.taglibs.taglibs-standard-spec

Distributionlib/apache-jstl

org.apache.taglibs:taglibs-standard-spec:jar:1.2.1

org.apache.taglibs.standard-impl

Distributionlib/apache-jstl

org.apache.xalan2.7.1


TryEclipseOrbit

org.apache.xml.serializer2.7.1


TryEclipseOrbit

29.2.9.2jetty-osgi-boot-jsp包
为了使用JSP你需要在OSGi容器中安装jetty-osgi-boot-jsp.jar。这个jar包可以在Maven仓库中心获取。它作为一个jetty-osgi-boot.jar延伸用于支持JSP。JettyJSPOSGi容器可以支持所有webapp的JSTLtag库。如果你的web应用将不需要做任何修改即可使用。

然而,如果你想使用其他的taglibs,你要确保它们被安装到OSGi容器中,并且定义了系统属性或在webapp的MANIFEST头部声明。这是有必要的,因为OSGi容器的类加载模式与使用JSP容器非常不同,webapp的MANIFEST文件如果没有包含足够的信息的话,那么OSGi环境将不允许JSP容器来获取和解析.jsp文件中的TLDs引用。

首先我们看下面这个修改过的MANIFEST例子,让你知道哪些是必须要的。这个例子使用了Springservlet框架:

Bundle-SymbolicName:com.acme.sample
Bundle-Name:WebSample
Web-ContextPath:taglibs
Import-Bundle:org.springframework.web.servlet
Require-TldBundle:org.springframework.web.servlet
Bundle-Version:1.0.0
Import-Package:org.eclipse.virgo.web.dm;version="[3.0.0,4.0.0)",org.s
pringframework.context.config;version="[2.5.6,4.0.0)",org.springframe
work.stereotype;version="[2.5.6,4.0.0)",org.springframework.web.bind.
annotation;version="[2.5.6,4.0.0)",org.springframework.web.context;ve
rsion="[2.5.6,4.0.0)",org.springframework.web.servlet;version="[2.5.6
,4.0.0)",org.springframework.web.servlet.view;version="[2.5.6,4.0.0)"

29.2.10使用Annotations/ServletContainerInitializers
注解是Servlet3.0和Servlet3.1规范的重要组成部分。为了在OSGiJetty容器中使用它们,你需要增加一些额外的依赖包到你的OSGi容器中:

Table29.5.注解的依赖包

Jar包 包名 路径
org.ow2.asm:asm-5.0.1.jar

org.objectweb.asm

Mavencentral

org.ow2.asm:asm-commons-5.0.1.jar

org.objectweb.asm.commons

Mavencentral

org.ow2.asm:asm-tree-5.0.1.jar

org.objectweb.asm.tree

Mavencentral

org.apache.aries:org.apache.aries.util-1.0.1.jar

org.apache.aries.util

Mavencentral

org.apache.aries.spifly:org.apache.aries.spifly.dynamic.bundle-1.0.1.jar

org.apache.aries.spifly.dynamic.bundle

Mavencentral

javax.annotation:javax.annotation-api-1.2.jar

javax.annotation-api

Mavencentral

jtaapiversion1.1.1(egorg.apache.geronimo.specs:geronimo-jta_1.1_spec-1.1.1.jar)


Mavencentral

javaxmailapiversion1.4.1(egorg.eclipse.jetty.orbit:javax.mail.glassfish-1.4.1.v201005082020.jar)


Mavencentral

jetty-jndi

org.eclipse.jetty.jndi

Distributionlib/

jetty-plus

org.eclipse.jetty.plus

Distributionlib/

jetty-annotations

org.eclipse.jetty.annotations

Distributionlib/

+重要
如果你想使用注解,你需要部署这些依赖包。

+提示
你可以部署这些jar包的最后一个版本,然而特定的版本已知是正确的,经过测试并在OSGi环境下运行过。

即便你的web应用不使用注解,你也应该部署这些jar包,因为你的应用可能依赖Jetty的模块或者使用javax.servlet.ServletContainerInitializer。这个接口需要注解的支持。

29.3Weld
Weld可以用来增加servlet、Listeners、Filters对CDI的支持。在Jetty9中配置是非常简单的。

1、启动时确保模块调用cdi

2、确保你的WEB-INF/web.xml包含如下内容:

复制代码

org.jboss.weld.environment.servlet.Listener



ObjectfactoryfortheCDIBeanManager
BeanManager
javax.enterprise.inject.spi.BeanManager

复制代码
这当你启动Jetty的时候,你将看到以下输出:

2015-06-1812:13:54.924:INFO::main:Logginginitialized@485ms
2015-06-1812:13:55.231:INFO:oejs.Server:main:jetty-9.3.1-SNAPSHOT
2015-06-1812:13:55.264:INFO:oejdp.ScanningAppProvider:main:Deploymentmonitor[file:///tmp/cdi-demo/webapps/]atinterval1
2015-06-1812:13:55.607:WARN:oeja.AnnotationConfiguration:main:ServletContainerInitializers:detected.Classhierarchy:empty
Jun18,201512:13:55PMorg.jboss.weld.environment.servlet.EnhancedListeneronStartup
INFO:WELD-ENV-001008:InitializeWeldusingServletContainerInitializer
Jun18,201512:13:55PMorg.jboss.weld.bootstrap.WeldStartup
INFO:WELD-000900:2.2.9(Final)
Jun18,201512:13:55PMorg.jboss.weld.environment.servlet.deployment.WebAppBeanArchiveScannerscan
WARN:WELD-ENV-001004:FoundbothWEB-INF/beans.xmlandWEB-INF/classes/META-INF/beans.xml.It''snotportabletousebothlocationsatthesametime.Weldisgoingtousefile:/tmp/jetty-0.0.0.0-8080-cdi-webapp.war-_cdi-webapp-any-8161614308407422636.dir/webapp/WEB-INF/beans.xml.
Jun18,201512:13:55PMorg.jboss.weld.bootstrap.WeldStartupstartContainer
INFO:WELD-000101:Transactionalservicesnotavailable.Injectionof@InjectUserTransactionnotavailable.Transactionalobserverswillbeinvokedsynchronously.
Jun18,201512:13:55PMorg.jboss.weld.interceptor.util.InterceptionTypeRegistry
WARN:WELD-001700:Interceptorannotationclassjavax.ejb.PostActivatenotfound,interceptionbasedonitisnotenabled
Jun18,201512:13:55PMorg.jboss.weld.interceptor.util.InterceptionTypeRegistry
WARN:WELD-001700:Interceptorannotationclassjavax.ejb.PrePassivatenotfound,interceptionbasedonitisnotenabled
Jun18,201512:13:56PMorg.jboss.weld.bootstrap.MissingDependenciesRegistryhandleResourceLoadingException
Jun18,201512:13:56PMorg.jboss.weld.environment.servlet.WeldServletLifecyclefindContainer
INFO:WELD-ENV-001002:Containerdetectionskipped-customcontainerclassloaded:org.jboss.weld.environment.jetty.www.wang027.comJettyContainer.
Jun18,201512:13:56PMorg.jboss.weld.environment.jetty.JettyContainerinitialize
INFO:WELD-ENV-001200:Jetty7.2+detected,CDIinjectionwillbeavailableinServletsandFilters.InjectionintoListenersshouldworkonJetty9.1.1andnewer.
Jun18,201512:13:56PMorg.jboss.weld.environment.servlet.ListenercontextInitialized
INFO:WELD-ENV-001006:org.jboss.weld.environment.servlet.EnhancedListenerusedforServletContextnotifications
Jun18,201512:13:56PMorg.jboss.weld.environment.servlet.EnhancedListenercontextInitialized
INFO:WELD-ENV-001009:org.jboss.weld.environment.servlet.ListenerusedforServletRequestandHttpSessionnotifications
2015-06-1812:13:56.535:INFO:oejsh.ContextHandler:main:Startedo.e.j.w.WebAppContext@6574b225{/cdi-webapp,file:///tmp/jetty-0.0.0.0-8080-cdi-webapp.war-_cdi-webapp-any-8161614308407422636.dir/webapp/,AVAILABLE}{/cdi-webapp.war}
2015-06-1812:13:56.554:INFO:oejs.ServerConnector:main:StartedServerConnector@7112f81c{HTTP/1.1,[http/1.1]}{0.0.0.0:8080}
2015-06-1812:13:56.587:INFO:oejus.SslContextFactory:main:x509={jetty.eclipse.org=jetty}wild={}alias=nullforSslContextFactory@3214ee6(file:///tmp/cdi-demo/etc/keystore,file:///tmp/cdi-demo/etc/keystore)
2015-06-1812:13:56.821:INFO:oejs.ServerConnector:main:StartedServerConnector@69176a9b{SSL,[ssl,http/1.1]}{0.0.0.0:8443}
2015-06-1812:13:56.822:INFO:oejs.Server:main:Started@2383ms

29.4Metro
Metro是WebService的参考实现,你可以简单的使用Metro对你的webservice和你的应用进行整合。步骤如下:

下载Metro安装包,解压到硬盘,使用$metro.home来代替解压路径。
创建$jetty.home/lib/metro文件夹。
将$metro.home/lib下的jar包拷贝到$jetty.home/lib/metro下面。
编辑start.ini文件,在结尾处增加OPTIONS=metro。
这就是所有的步骤,完成后即可把Jetty和Metro进行整合。下面是启动后的输出:

[2093]java-jarstart.jar

2013-07-2615:47:53.480:INFO:oejs.Server:main:jetty-9.0.4.v20130625
2013-07-2615:47:53.549:INFO:oejdp.ScanningAppProvider:main:Deploymentmonitor[file:/home/user/jetty-distribution-9.3.11.v20160721/webapps/]atinterval1
Jul26,20133:47:53PMcom.sun.xml.ws.transport.http.servlet.WSServletContextListenercontextInitialized
INFO:WSSERVLET12:JAX-WScontextlistenerinitializing
Jul26,20133:47:56PMcom.sun.xml.ws.server.MonitorBasecreateRoot
INFO:Metromonitoringrootnamesuccessfullysetto:com.sun.metro:pp=/,type=WSEndpoint,name=/metro-async-AddNumbersService-AddNumbersImplPort
Jul26,20133:47:56PMcom.sun.xml.ws.transport.http.servlet.WSServletDelegate
INFO:WSSERVLET14:JAX-WSservletinitializing
2013-07-2615:47:56.800:INFO:oejsh.ContextHandler:main:Startedo.e.j.w.WebAppContext@75707c77{/metro-async,file:/tmp/jetty-0.0.0.0-8080-metro-async.war-_metro-async-any-/webapp/,AVAILABLE}{/metro-async.war}
2013-07-2615:47:56.853:INFO:oejs.ServerConnector:main:StartedServerConnector@47dce809{HTTP/1.1}{0.0.0.0:8080}

三十、Ant和Jetty
AntJetty插件是Jetty9jetty-ant模块下的一部分。这个插件让通过Ant启动Jetty成为可能,并且将Jetty应用嵌入到你的构建过程中。它提供绝大部分Maven同样的功能。需要添加以下依赖:


org.eclipse.jetty
jetty-ant

30.1项目前期准备
为了在Ant中运行你的Jetty,你需要Jetty安装包和jetty-ant的jar包。步骤如下:

下载Jetty安装包,并解压到本地。
获得thejetty-antJar。
在你的项目中新建jetty-lib/文件夹。
拷贝Jetty所有的jar包到jetty-lib文件夹下,拷贝时注意去掉层级关系,所有的jar包都要在jetty-lib路径下。
拷贝jetty-ant.jar到jetty-lib文件夹下。
在项目中新建jetty-temp文件夹。
现在你已经准备好编辑或创建build.xml文件了。

30.2build.xml文件准
以一个空的build.xml文件中开始。



增加一个标签来引用所有可用的Jettytask







接下来你要为运行的Jetty增加新的任务

复制代码









复制代码
这是需要的最少的配置。现在你可以启动Jetty,默认端口为8080。

30.3通过Ant启动Jetty
在命令行中输入以下内容:

>antjetty.run

30.4配置Jetty容器
一系列的配置属性可以帮助你设置Jetty的运行环境,这样你的web应用将有你需要的所有资源:

端口和连接:

为了配置启动端口你需要定一个连接。首先你需要配置一个标签用于定义连接:

复制代码














复制代码
+技巧
你可以将端口设置为0,那么Jetty启动时将自动分配一个可用的端口。你可以通过访问系统属性jetty.ant.server.port和jetty.ant.server.host获得启动的信息。

登录服务

如果你的应用需要身份认证和登录服务,你可以在Jetty容器中进行配置。这里有一个例子用来展示如何配置一个org.eclipse.jetty.security.HashLoginService服务:

复制代码














复制代码
请求日志

requestLog选项运行你为Jetty实例指定一个请求日志。你可以使用org.eclipse.jetty.server.NCSARequestLog或者你自己的实现类:

复制代码










复制代码
临时目录

你可以把一个文件夹配置为临时目录用于存储文件,例如编译后的jsp,通过tempDirectory选项进行配置:

复制代码










复制代码
其他context处理器

你有可能会在你程序运行的同时想要运行其他的context处理器,你可以通过进行指定,在用之前首先定义一个

复制代码




resource="tasks.properties"loaderref="jetty.loader"/>
classpathref="jetty.plugin.classpath"loaderref="jetty.loader"/>








复制代码
系统参数

为了方便你可以定义系统参数,通过使用元素:

复制代码













复制代码
Jettyxml文件

如果你有大量的文件用来配置容器,你可以通过xml来配置管理:

复制代码










复制代码
扫描文件改动

最有用的模块是运行Jetty插件来自动扫描文件改动并重启服务。scanIntervalSeconds选项控制扫描的频率,默认值为0不扫描,下面例子指定扫描为5秒:

复制代码










复制代码
停止运行

在普通模式中(daemon="false"),任务将会一直运行直到输入Ctrl+C,可以通过配置元素来配置停止端口:

复制代码













复制代码
为了在Ant中停止Jetty的运行,输入以下:

>antjetty.stop

30.5部署一个web应用
可以为org.eclipse.jetty.ant.AntWebAppContext类增加一个标签,并配置一个webApp名字,然后增加一个标签来描述你需要运行的web项目。下面的例子部署了一个web应用,应用在foo/文件夹下,context的Path为“/”:

复制代码





classpathref="jetty.plugin.classpath"loaderref="jetty.loader"/>






复制代码
30.5.1部署一个war文件
不需要解压一个war文件,可以很方便的部署一个war文件:

复制代码





classpathref="jetty.plugin.classpath"loaderref="jetty.loader"/>






复制代码
30.5.2部署多个web应用
你也可以同时部署多个web应用,配置如下:

复制代码





classpathref="jetty.plugin.classpath"loaderref="jetty.loader"/>








复制代码
30.6配置web应用
org.eclipse.jetty.ant.AntWebAppContext类是org.eclipse.jetty.webapp.WebAppContext类的扩展,你可以通过增加同属性set方法来配置它(不需要设置或新增前缀)。

这里有一个例子,指定了web.xml(与AntWebAppContext.setDescriptor()功能相同)和web应用的临时目录(与AntWebAppContext.setTempDirectory()功能相同)。

复制代码





classpathref="jetty.plugin.classpath"loaderref="jetty.loader"/>






复制代码
其他额外的对AntWebAppContext配置如下;

额外的classes和jar包

如果你的web应用的classes和jar包不单单放在WEB-INF下面,你可以使用元素来配置它们,例子如下:

复制代码





classpathref="jetty.plugin.classpath"loaderref="jetty.loader"/>















复制代码
context属性

Jetty允许你对web应用的ServletContext设置属性。你可以在contextxml文件中进行配置,为了方便也可以在build文件中进行配置:

复制代码





classpathref="jetty.plugin.classpath"loaderref="jetty.loader"/>










复制代码
jetty-env.xml文件

如果你使用一些新特性如JNDJ在你的应用程序中,你需要在WEB-INF/jetty-env.xml文件中配置资源。你需要使用jettyEnvXml属性来告诉Ant配置文件放在那里:

复制代码





classpathref="jetty.plugin.classpath"loaderref="jetty.loader"/>








复制代码
contextXml文件

您可能会喜欢或甚至需要做一些高级配置您的Web应用程序以外的蚂蚁构建文件。在这种情况下,您可以使用ant插件在部署之前应用到您的Web应用程序的标准上下文XML配置文件。要注意,上下文XML文件的设置覆盖了在生成文件中定义的属性和嵌套元素的设置。???

复制代码
projectname="Jetty-Antintegrationtest"basedir=".">




classpathref="jetty.plugin.classpath"loaderref="jetty.loader"/>







献花(0)
+1
(本文系thedust79首藏)