基于Jetty的内嵌式服务器

一个嵌入式的Jetty servlet容器可以让web使用Java应用而不用打包成正式的web应用的形式。

 

示例程序Step1 Driver 演示了一个基于Jetty的简单服务。它创建了一个servlet容器的实例,将一个servlet class映射到一个URI,并且使用一些URL来调用这个servlet。

Jetty的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 ;

               // 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( ... )

            ) ;



为了配置SocketListener自己,必须使用一个<Call>来调用它的setHost()方法,既然这个方法遵循了 JavaBean的命名规则,示例代码因此使用了<Set> element(4)作为一种快捷方式。在后台,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( ... ) ;


Jetty 小组的英明在于这个XML配置文件的进一步深入处理:我们可以注意到列表1中所有的Jetty特定的调用都是element和属性的值,而不是名字,这就意味着XML配置文件可以被用在任何类上,而不仅仅是Jetty的类中。根据你的应用程序的编写方式,你可以全部使用Jetty的XML配置文件来配置。

可执行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的代码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值