1. 程式人生 > >Jetty 9嵌入式開發

Jetty 9嵌入式開發

當前Jetty網址上推薦使用的穩定版本:Jetty9.0。

介紹

       直接連結:

       Jetty有一個標語,“不要部署你的應用在Jetty上,部署Jetty在你的應用中”。這意味著可選擇使用Jetty捆綁你的應用作為一個標準WAR進行部署。Jetty設計成一個軟體元件,可以例項化並且使用在Java程式中,例如:如何POJO。但是另外一種方法,以嵌入式模式執行Jetty,這意味著把HTTP模組放入到你的應用中,而不是把你的應用放入到HTTP服務中。

       本教程引導你逐步從最簡單的Jetty服務例項到使用標準部署描述執行多個Web應用。大部分示例的原始碼是標準Jetty專案的一部分。

       在學習該教程之前,完成一個HelloWorld教程是值得的。該教程可以在“嵌入式Jetty網路研討會記錄”中找到。

       Jetty版本:本教程的程式碼來自於Jetty7,但是也應該在Jetty 8中可以使用。對於最新的穩定版本,參考最新發行版的連結程式碼。可能與本教程中給出的程式碼例子有稍微的不同。

概述

       為了嵌入Jetty服務,通常執行下面的步驟:

       1)建立一個服務

       2)新增和配置聯結器

       3)新增和配置處理器

       4)新增和配置Servlet、Webapp到處理器

       5)啟動服務

       6)等待(join服務防止主執行緒退出)

建立一個服務

       下面的程式碼來自於SimplestServer.jar,例項化和執行一個最簡單的Jetty服務

public class SimplestServer

{

   public static void main(String[] args) throws Exception

    {

       Server server = new Server(8080);

       server.start();

       server.join();

    }

}

       在埠8080上執行一個HTTP服務。這不是非常有用的服務,因為它不處理,對於每個請求只是返回一個404錯誤。

編寫處理器

       為了生成請求的響應,Jetty要求在服務上設定一個Handler。一個處理器可能:

1)  檢查和修改HTTP請求

2)生成完整的HTTP詳情

3)呼叫其他的處理器(參見HandlerWrapper)

4)選擇一個或者多個處理器呼叫(參考HandlerCollection)

Hello world處理器:

下面程式碼基於HelloHandler.java,顯示一個簡單的Helloworld處理器。

public classHelloHandler extends AbstractHandler

{

    public void handle(String target,RequestbaseRequest,HttpServletRequest request,HttpServletResponse response)

        throws IOException, ServletException

    {

        response.setContentType("text/html;charset=utf-8");

       response.setStatus(HttpServletResponse.SC_OK);

        baseRequest.setHandled(true);

       response.getWriter().println("<h1>HelloWorld</h1>");

    }

}

傳遞給handle方法的引數包括:

1)  target - 請求的目標,它可以是一個URI或者命名分發器的名稱

2) baseRequest – Jetty可變請求物件,它總是解包的

3)  request - 不可變的請求物件,它可能已經被封裝

4) response - 響應,它可能已經被封裝

處理器設定請求的狀態,內容型別,在使用writer生成請求體之前標註請求已經處理(後續就不再處理)。

下面的程式碼來自於OneHandler.java,顯示Jetty服務如何使用該處理器。

public staticvoid main(String[] args) throws Exception

{

    Server server = new Server(8080);

    server.setHandler(new HelloHandler());

    server.start();

    server.join();

}

現在你知道基於Jetty編寫一個HTTP服務所需要了解的所有東西。然而,複雜的請求處理通常使用多處理器構建。我們在後面章節中看看它是如何組合處理器的。你能檢視Jetty的org.eclipse.jetty.server.handler包中有那些可用處理器。

配置連線

為了配置服務使用的HTTP連線。你能設定服務上的一個或者多個聯結器。你能詳細配置每個連結,例如:介面、埠、緩衝大小,超時時間等。

下面的程式碼基於ManyConnectors.java,顯示如何為HelloWorld示例設定和配置聯結器。

public class ManyConnectors

{

   public static void main(String[] args) throws Exception

    {

       Server server = new Server();

       SelectChannelConnector connector0 = new SelectChannelConnector();

       connector0.setPort(8080);

       connector0.setMaxIdleTime(30000);

       connector0.setRequestHeaderSize(8192);

       SelectChannelConnector connector1 = new SelectChannelConnector();

       connector1.setHost("127.0.0.1");

       connector1.setPort(8888);

       connector1.setThreadPool(new QueuedThreadPool(20));

       connector1.setName("admin");

       SslSelectChannelConnector ssl_connector = newSslSelectChannelConnector();

       String jetty_home =

         System.getProperty("jetty.home","../jetty-distribution/target/distribution");

       System.setProperty("jetty.home",jetty_home);

       ssl_connector.setPort(8443);

       SslContextFactory cf = ssl_connector.getSslContextFactory();

       cf.setKeyStore(jetty_home + "/etc/keystore");

       cf.setKeyStorePassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");

       cf.setKeyManagerPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");

       server.setConnectors(new Connector[]{ connector0, connector1,ssl_connector });

       server.setHandler(new HelloHandler());

       server.start();

       server.join();

    }

}

理解處理器集合、封裝和範圍

       複雜請求處理通常構建多個處理器,能夠以各種方式組合:

1) 處理器集合:保留其他處理器集合,依次呼叫每個處理器。對於合併統計和日誌處理器(生成請求的處理器)是有用的。

2) 處理器列表:一個處理器集合,依次呼叫處理器直到丟擲異常、委派響應或request.isHandled返回true。它能作為合併處理器使用,有條件的處理一個請求。

3) 處理器封裝:一個處理器基類可以用於菊花鏈處理程式,以面向方面程式設計風格組合在一起。例如,一個標準的Web應用通過上下文、會話、安全和Servlet處理器的鏈式實現。

4) 內容處理器集合:使用最長的請求URI字首(contextPath)來選擇指定的ContextHandler來處理請求。

參見如何編寫Jetty處理器。

配置檔案服務

下面程式碼來自於FileServer.java,使用HandleList組合ResourceHandler和DefaultHandler。

public class FileServer

{

   public static void main(String[] args) throws Exception

    {

       Server server = new Server();

       SelectChannelConnector connector = new SelectChannelConnector();

       connector.setPort(8080);

       server.addConnector(connector);

       ResourceHandler resource_handler = new ResourceHandler();

       resource_handler.setDirectoriesListed(true);

       resource_handler.setWelcomeFiles(new String[]{ "index.html"});

       resource_handler.setResourceBase(".");

       HandlerList handlers = new HandlerList();

       handlers.setHandlers(new Handler[] { resource_handler, newDefaultHandler() });

       server.setHandler(handlers);

       server.start();

       server.join();

    }

}

       資源處理器首先傳遞給請求,檢視在本地目錄下是否有滿足的檔案。如果沒有找到一個檔案,請求傳遞給預設的處理器生成一個404錯誤(或favicon.ico)。

使用XML配置的檔案伺服器

       現在是時候讓你記住JettyXML配置格式能夠渲染簡單的Java程式碼到XML配置。所以上面的檔案伺服器例子可以使用Jetty XML來編寫,如下。

<?xml version="1.0"?>

<!DOCTYPE Configure PUBLIC"-//Jetty//Configure//EN""http://www.eclipse.org/jetty/configure.dtd">

<Configure id="FileServer"class="org.eclipse.jetty.server.Server">

   <Call name="addConnector">

     <Arg>

         <Newclass="org.eclipse.jetty.server.nio.SelectChannelConnector">

           <Set name="port">8080</Set>

         </New>

     </Arg>

   </Call>

   <Set name="handler">

     <New class="org.eclipse.jetty.server.handler.HandlerList">

       <Set name="handlers">

         <Arraytype="org.eclipse.jetty.server.Handler">

           <Item>

             <Newclass="org.eclipse.jetty.server.handler.ResourceHandler">

               <Setname="directoriesListed">true</Set>

              <Setname="welcomeFiles">

                <Arraytype="String"><Item>index.html</Item></Array>

              </Set>

               <Setname="resourceBase">.</Set>

             </New>

           </Item>

           <Item>

             <Newclass="org.eclipse.jetty.server.handler.DefaultHandler">

             </New>

           </Item>

         </Array>

       </Set>

     </New>

   </Set>

</Configure>

       你可以從FileServerXml.java中執行這個XML檔案。

public class FileServerXml

{

   public static void main(String[] args) throws Exception

    {

       Resource fileserver_xml =Resource.newSystemResource("fileserver.xml");

       XmlConfiguration configuration = newXmlConfiguration(fileserver_xml.getInputStream());

       Server server = (Server)configuration.configure();

       server.start();

       server.join();

    }

}

使用Spring配置檔案伺服器

       你也能使用Spring框架聚合Jetty服務,上面的檔案伺服器示例可以使用Spring配置重寫,如下:

<beans>

 <bean id="Server"class="org.eclipse.jetty.server.Server" init-method="start"destroy-method="stop">

   <property name="connectors">

     <list>

       <bean id="Connector"class="org.eclipse.jetty.server.nio.SelectChannelConnector">

         <property name="port" value="8080"/>

       </bean>

     </list>

   </property>

   <property name="handler">

     <bean id="handlers"class="org.eclipse.jetty.server.handler.HandlerList">

       <property name="handlers">

         <list>

           <beanclass="org.eclipse.jetty.server.handler.ResourceHandler">

              <propertyname="directoriesListed" value="true"/>

              <propertyname="welcomeFiles">

                <list>

                  <value>index.html</value>

                </list>

              </property>

              <propertyname="resourceBase" value="."/>

           </bean>      

           <beanclass="org.eclipse.jetty.server.handler.DefaultHandler"/>

         </list>

       </property>

     </bean>

   </property>

 </bean>

</beans>

設定上下文

       ContextHandler是是HandlerWrapper,只負責請求符合配置上下路徑的URL字首。

       符合上下文路徑(有它們路徑方法)的請求將進行相應的更新,以下可選上下文特徵被正確的應用。

* 一個執行緒內容類載入器

* 屬性的集合

* 初始化引數集合

* 基礎資源(又名文件根目錄)

* 虛擬主機名集合

沒有匹配的請求不進行處理。

       下面的程式碼基於OneContext.java,設定上下文路徑和hello處理器的類載入器。

public class OneContext

{

   public static void main(String[] args) throws Exception

    {

       Server server = new Server(8080);

       ContextHandler context = new ContextHandler();

       context.setContextPath("/hello");

       context.setResourceBase(".");

       context.setClassLoader(Thread.currentThread().getContextClassLoader());

       server.setHandler(context);

       context.setHandler(new HelloHandler());

       server.start();

       server.join();

    }

}

建立Servlet

       Servlet是提供應用邏輯和處理HTTP請求的標準方法。Servlet就像約束標準方法的處理器對映指定URI給指定的Servlet。下面的程式碼基於HelloServlet.java。

public class HelloServlet extendsHttpServlet

{

   private String greeting="Hello World";

   public HelloServlet(){}

   public HelloServlet(String greeting)

    {

       this.greeting=greeting;

    }

   protected void doGet(HttpServletRequest request, HttpServletResponseresponse) throws ServletException, IOException

    {

       response.setContentType("text/html");

       response.setStatus(HttpServletResponse.SC_OK);

       response.getWriter().println("<h1>"+greeting+"</h1>");

       response.getWriter().println("session=" +request.getSession(true).getId());

    }

}

設定ServletContext

       ServletContextHandler是一個支援標準Servlet的專用ContextHandler。下面的程式碼來自於OneServletContext,顯示三個HelloworldServlet例項註冊到一個ServletContextHandler上。

public class OneServletContext

{

   public static void main(String[] args) throws Exception

    {

       Server server = new Server(8080);

       ServletContextHandler context = newServletContextHandler(ServletContextHandler.SESSIONS);

       context.setContextPath("/");

       server.setHandler(context);

       context.addServlet(new ServletHolder(newHelloServlet()),"/*");

       context.addServlet(new ServletHolder(new HelloServlet("BuongiornoMondo")),"/it/*");

       context.addServlet(new ServletHolder(new HelloServlet("Bonjour leMonde")),"/fr/*");

       server.start();

       server.join();

    }

}

設定Web應用上下文

       一個Web應用上下文是ServletContextHandler的變種,使用標準的佈局和web.xml配置Servlet、過濾器和其它特徵。

public class OneWebApp

{

   public static void main(String[] args) throws Exception

    {

       String jetty_home =System.getProperty("jetty.home","..");

       Server server = new Server(8080);

       WebAppContext webapp = new WebAppContext();

       webapp.setContextPath("/");

       webapp.setWar(jetty_home+"/webapps/test.war");

       server.setHandler(webapp);

       server.start();

       server.join();

    }

}

       如果不熟期間,你沒有組裝應用程式為WAR檔案,你可以從源元件上執行它,如下:

public class OneWebAppUnassembled

{

   public static void main(String[] args) throws Exception

    {

       Server server = new Server(8080);

       WebAppContext context = new WebAppContext();

       context.setDescriptor(webapp+"/WEB-INF/web.xml");

       context.setResourceBase("../test-jetty-webapp/src/main/webapp");

       context.setContextPath("/");

       context.setParentLoaderPriority(true);

       server.setHandler(context);

       server.start();

       server.join();

    }

}

配置上下文處理器集合

       上下文處理器集合使用最長請求URI字首選擇指定的上下文。下面的示例在單個Jetty服務上組合前面兩個示例。

public class ManyContexts

{

   public static void main(String[] args) throws Exception

    {

       Server server = new Server(8080);

       ServletContextHandler context0 = newServletContextHandler(ServletContextHandler.SESSIONS);

       context0.setContextPath("/ctx0");

       context0.addServlet(new ServletHolder(newHelloServlet()),"/*");

       context0.addServlet(new ServletHolder(new HelloServlet("BuongiornoMondo")),"/it/*");

       context0.addServlet(new ServletHolder(new HelloServlet("Bonjour leMonde")),"/fr/*");

       WebAppContext webapp = new WebAppContext();

       webapp.setContextPath("/ctx1");

       webapp.setWar(jetty_home+"/webapps/test.war");

       ContextHandlerCollection contexts = new ContextHandlerCollection();

       contexts.setHandlers(new Handler[] { context0, webapp });

       server.setHandler(contexts);

       server.start();

       server.join();

    }

}

嵌入式JSP

       嵌入式JSP支援可能有點令人困惑,如果你檢視Jetty發行版lib/jsp目錄下的JAR包。這是因為我們為Eclipse封裝了JSP軟體集,標記為OSGI軟體集,不能直接從Maven Central中直接下載。在Maven中心中有可用的依賴,因為它們有OSGI軟體集自己實際原始碼。OSGI軟體集簡化Maven中心artifact,解壓成多個擴充套件的bundle。

       你能使用的示例如下:

INFO]org.eclipse.jetty:jetty-jsp-2.1:jar:7.2.2-SNAPSHOT

[INFO] +-org.eclipse.jetty:jetty-util:jar:7.2.2-SNAPSHOT:provided

[INFO] +-org.mortbay.jetty:jsp-2.1-glassfish:jar:2.1.v20100127:provided

[INFO] | +- org.eclipse.jdt.core.compiler:ecj:jar:3.5.1:provided

[INFO] | +- org.mortbay.jetty:jsp-api-2.1-glassfish:jar:2.1.v20100127:provided

[INFO] | \- ant:ant:jar:1.6.5:provided

[INFO] \-javax.servlet:servlet-api:jar:2.5:provided

       你應該能夠依賴於一個嵌入式聚合,我們提供獲取這些依賴,沒有任何問題。

http://repo2.maven.org/maven2/org/eclipse/jetty/aggregate