Blogger Scott

          Jetty 源碼分析

          一、 總括

               你了解Jetty 嗎,就像我們所熟知的Tomcat一樣, Jetty是一個免費(fèi)的開放源碼的100%純Java的Http服務(wù)器和Servlet容器。



               Jetty具備以下特點(diǎn):

               快速高效

               。Jetty是最快的Servlet服務(wù)器之一

               。Jetty可以處理上千個并發(fā)連接
               小巧嵌入
               。Jetty的jar只有600多K
               。可動態(tài)嵌入到應(yīng)用程序,適合開發(fā)web2.0等應(yīng)用

               應(yīng)用廣泛

               。開源項目有Geronimo, JBoss, JOnAS

               。商業(yè)項目有IBM Tivoli, Sonic MQ and Cisco SESM等

               可到Jetty網(wǎng)站 http://jetty.mortbay.org/jetty/ 查看最新信息

               本文將通過對Jetty最新穩(wěn)定版 Jetty5.1.5RC2 源碼的研究,向讀者展示Jetty在設(shè)計方面使用的不同設(shè)計理念, 希望對廣大開發(fā)者在設(shè)計自己的系統(tǒng)時有所幫助。

               Jetty按照功能可以分為四個主個主要的部分,HttpServer, HttpContext,HttpHandler,HttpListener,詳見如下類圖:

          <圖 1-1>

           

          二、HttpServer及配置

               對于初次接觸Jetty的人一定會對上圖感到迷惑,其實(shí)在Jetty中 HttpServer是一個服務(wù)器的核心控制類, 我們可以看到,其它的組件類都是由該類擴(kuò)展開來,HttpServer的作用就是在一系列的監(jiān)聽器類和處理器類之間搭起了一個橋梁,有效的控制著消息在系統(tǒng)內(nèi)的傳遞,如下圖:
          <圖 1-2 >
               HttpServer職責(zé)是接受從HttpListener傳遞過來的request(請求),HttpServer通過對request的Host(主機(jī))或Path(路徑)進(jìn)行匹配,然后分發(fā)給相應(yīng)的HttpContext(可以理解為一個web application)。
               這里舉個例子,假設(shè)我們現(xiàn)在要建立一個提供靜態(tài)頁面web服務(wù),頁面內(nèi)容在c:\root \下,可以通過如此配置HttpServer:
               HttpServer server = new HttpServer(); // 創(chuàng)建一個新的HttpServer
               SocketListener listener = new SocketListener(); // 創(chuàng)建一個新監(jiān)聽器
               listener.setPort(8080);// 設(shè)置監(jiān)聽端口為8080
               server.addListener(listener);// 將監(jiān)聽類注冊到server中
               HttpContext context = new HttpContext(); // 創(chuàng)建一個新HttpContext
               context.setContextPath("/app/*"); // 設(shè)置訪問路徑
               context.setResourceBase("c:/root/"); // 設(shè)置靜態(tài)資源路徑
               context.addHandler(new ResourceHandler()); // 為這個HttpContext添加一個靜態(tài)資源處理器
               server.addContext(context); // 將這個HttpContext注冊到server中
               server.start();// 最后啟動這個server
               當(dāng)我們要建立一個提供動態(tài)頁面web服務(wù)時, 假設(shè)我們自己的 web 應(yīng)用放在Jetty目錄下的webapps下并打好包文件名為myapp.war, 可以通過如此配置HttpServer:
               Server server = new Server(); // 創(chuàng)建一個新的HttpServer
               SocketListener listener = new SocketListener();// 創(chuàng)建一個新監(jiān)聽器
               listener.setPort(8080); // 設(shè)置監(jiān)聽端口為8080
               server.addListener(listener ); // 將監(jiān)聽類注冊到server中
               server.addWebApplication("myapp","./webapps/myapp/"); // 將這個web應(yīng)用注冊到這個Server中
               server.start(); // 最后啟動這個server
               短短數(shù)行代碼就可創(chuàng)建一個web服務(wù)器并啟動它,這有點(diǎn)類似于我們windows中的即插即用的概念,需要什么就添加什么,把這些類以HttpServer為核心組合在一起,就可以完成強(qiáng)大的功能。
           

          三、Jetty Server

               1.上面我們探討了HttpServer的啟動,讀者一定還存在這樣疑問,整個Jetty 服務(wù)器是怎樣啟動的?
               首先我們可以在圖 1-1 看到左下角有一個Server類,這個類實(shí)際上繼承了HttpServer,當(dāng)啟動Jetty服務(wù)器時,具體來說,在Jetty根目錄下命令行下如輸入 JAVA -jar start.jar etc/demo.xml,注意這里有一個配置文件 demo.xml做為運(yùn)行參數(shù),這個參數(shù)也可以是其它的配置文件,也可是多個xml配置文件,其實(shí)這個配置文件好比我們使用struts時的struts -config.xml文件,將運(yùn)行Server需要用到的組件寫在里面,比如上一節(jié)中HttpServer的配置需要的組件類都可以寫在這個配置文件中。
               2.我們自己部署到Jetty的webapps目錄下的web application,Jetty如何運(yùn)行我們自己的web application?
               首先當(dāng)我們按上述方法啟動Jetty Server時,就會調(diào)用Server類里面的main方法,這個入口方法首先會構(gòu)造一個Server類實(shí)例(其實(shí)也就構(gòu)造了一個 HttpServer),創(chuàng)建實(shí)例過程中就會構(gòu)造XmlConfiguration類的對象來讀取參數(shù)配置文件,之后再由這個配置文件產(chǎn)生的 XmlConfiguration對象來配置這個Server,配置過程其實(shí)是運(yùn)用Java的反射機(jī)制調(diào)用Server的方法并傳入配置文件中所寫的參數(shù)來向這個Server添加HttpListener,HttpContext,HttpHandler,web application(對應(yīng)我們自己部署的web應(yīng)用)。
               添加我們自己的web application過程中相應(yīng)的就會讀取我們所熟知的/WEB-INF/web.xml來創(chuàng)建一個WebApplicationContext(這個類繼承了HttpContext)的實(shí)例,同時也會創(chuàng)建WebApplicationContext自身的ServletHandler(實(shí)現(xiàn)了 HttpHandler接口),注意到ServletHandler中包含一組ServletHolder指向?qū)嶋H的Servlet,譬如說我們在 web.xml文件中配置了兩個Filter和一個Servlet,這里就會有三個ServletHolder,實(shí)際處理請求時 ServeletHandler就會依次調(diào)用這三個ServletHolder傳入request,response處理(實(shí)際最后交給這兩個 Filter和Servlet處理),這樣我們自己做好的一個 web應(yīng)用就掛載到這個Server上了,可以接受客戶端相應(yīng)的request(請求)。
           

          四、運(yùn)行原理(請參考如下時序圖)

          <圖 1-7 >

               上圖展示了一個request的處理過程,首先HttpListener監(jiān)聽到客戶端發(fā)來的請求創(chuàng)建一個HttpConnection實(shí)例(封裝了連接細(xì)節(jié),比如從Socket連接中獲取的輸入流和輸出流), HttpConnection對象構(gòu)建過程中會創(chuàng)建Jetty內(nèi)部自定義的HttpRequest和HttpResponse對象,接著 HttpListener會調(diào)用這個HttpConnection實(shí)例的handle方法, HttpConnection實(shí)例就調(diào)用HttpRequest對象的read()方法讀取信息,調(diào)用HttpServer的service方法以 HttpRequest,HttpResponse為參數(shù)傳給HttpServer,HttpServer又將HttpRequest和 HttpResponse分發(fā)給相應(yīng)的HttpCotext,HttpContext最后將HttpRequest和HttpResponse交給自身的 HttpHandler 處理,在這里HttpRequest,HttpResponse被再次封裝為ServletHttpRequest和 ServletHttpResponse,其實(shí)這兩個類實(shí)現(xiàn)了我們所熟知的HttpServletRequest和 HttpServletResponse接口。

           

          五、高級性能

               1.HttpHandler:

               該接口的實(shí)現(xiàn)類用于處理HttpContext分發(fā)過來的reqeust,不同的實(shí)現(xiàn)類的有不同的處理功能,這里介紹幾常用的HttpHandler實(shí)現(xiàn)類:
               ReourceHandler:用于處理靜態(tài)內(nèi)容,如以擴(kuò)展名為.html的文件

               SecurityHandler:提供基本的安全驗證

               ForwardHandler:轉(zhuǎn)發(fā)一個request到另一個url

               ServletHandler:用于將request交由具體的Servlet類進(jìn)行處理
               2.當(dāng)你在看圖 1-2 時候會注意到HttpServer和HttpListener,HttpServer與HttpContext,HttpContext與 HttpHandler存在一對多的關(guān)系,下面就介紹一下它們之間的這種關(guān)系如何通過程序來配置.

               HttpListener & HttpServer:

               HttpListener是所有監(jiān)聽器類的接口,如圖中的SocketListener (基于傳統(tǒng)的Socket技術(shù))就實(shí)現(xiàn)了該接口,Jetty還有其它的實(shí)現(xiàn)該接口類,如SocketChannelListener(基于NIO技術(shù))類等,HttpListener職責(zé)主要是在服務(wù)器啟動后監(jiān)聽相應(yīng)端口的來自客戶端請求并建立連接(圖 1-1 中所示用HttpConnection封裝連接細(xì)節(jié)),監(jiān)聽器可在同個IP上開啟多個端口為同一個HttpServer 進(jìn)行監(jiān)聽,所以HttpListener和HttpServer是多對一的關(guān)系,如下圖:

          <圖 1-3 >

               配置代碼:
               HttpServer server = new HttpServer();
               HttpListenrer listener1 = new SocketChanneListener();
               Listener1.setPort(8080);
               HttpListenrer listener1 = new SocketListener();
               Listener1.setPort(8443);
               server.addListener(listener1);
               server.addListener(listener2);
           

               HttpContext & HttpHandler:

               HttpContext相當(dāng)于對應(yīng)客戶端請求的URL或某個虛擬機(jī), 其子類中包含若干個HttpHandler, 當(dāng)接受到request(請求)時,HttpContext會依次(按某個預(yù)定的次序)把request交給這些HttpHandler處理,直到這個 request被標(biāo)示處理過為止, 需要注意的是這個request可能被多個HttpHandler處理,但只能有一個HttpHandler能標(biāo)示這個request已被處理過.

               一個典型的HttpContext有用于安全處理、靜態(tài)資源處理及Servlet類的 HttpHandler,如下圖:
          <圖 1-4>
               配置代碼:
               HttpContext context = new HttpContext();
               context.setContextPath(“/myapp/*”);
               HttpHandler securitHandler = new SecurityHandler();
               HttpHandler resourceHandler = new ResourceHandler();
               HttpHandler servletHandler = new ServletHandler();
               context.addHandler(securitHandler);
               context.addHandler(resourceHandler);
               context.addHandler(servletHandler);
           
               HttpServer & HttpContext:
               一般的HTTP服務(wù)器軟件可以同時處理多個web application,同樣一個HttpServer可以包含多個HttpContext,如下圖可以通過同一個端口的監(jiān)聽類來映射多個 HttpContext:

          <圖 1-5 >

               配置代碼:
               HttpServer server = new HttpServer();
               HttpContext context1 = new HttpContext();
               context1.setContextPath(“/app1/*”);
               HttpContext context2 = new HttpContext();
               context2.setContextPath(“/app2/*”);
               server.addContext(context1);
           
               HttpServer & HttpLister & HttpContext:

               另外Jetty對多網(wǎng)卡(多個IP地址,不同的主機(jī)名)的服務(wù)器也提供了很好的支持,每個 HttpContext都有自身的HttpServer:

          <圖 1-6 >

               配置代碼:
               HttpServer server1 = new HttpServer();
               SocketListener listener1 = new SocketListener();

               listener1.setHost(“www.app1.com”);//orListener1.setHost(“www.app2.com”)

               listener2.setPort(80);

               HttpContext context1 = new HttpContext();

               context1.setContextPath(“/”);

               server1.addListener(listener1);

               server1.addContext(context1);

           
               3.Jetty對高并發(fā)的支持
          <圖 1-8>
               如果多用戶請求服務(wù)就會涉及到多線程的管理,如圖 1-8,Jetty中主要由ThreadPool負(fù)責(zé)管理多線程,注意其中Pool.PondLife是Pool的一個內(nèi)部接口, ThreadPool.PoolThread是ThreadPool的一個內(nèi)部線程類,我們看到Pool.PondLife和Pool存在一個聚集的關(guān)系,實(shí)際上Pool對象中存放在是一個個ThreadPool.PoolThread線程對象,當(dāng)有新用戶連接上Server時,ThreadPool就從Pool中取一個空閑的線程為當(dāng)前用戶連接服務(wù)。
           

          六、小結(jié)

               本文通過圖示簡要介紹了Jetty整個體系架構(gòu)和主要的組件類及服務(wù)器的啟動執(zhí)行過程,其實(shí)Jetty 通常被用來做為內(nèi)嵌的Web Server來使用,一些常見的服務(wù)器軟件,如Apache Cocoon、JBoss ,JOnAs等都會采用Jetty作為Web解決方案;另外由于Jetty在性能及穩(wěn)定性要優(yōu)于同類HTTP Server的原因,Jetty已在國外已很流行,鑒于這一點(diǎn),本文作者可以預(yù)測在不久的將來Jetty同樣也會在國內(nèi)流行開來。

           
          附:
          來源:http://blog.leiling.com/CALM/archive/2005/12/23/106662.aspx
          作者聯(lián)系方式:陳應(yīng)剛 dycyg@yahoo.com 熊紅陽

          posted on 2007-05-21 22:30 江天部落格 閱讀(4668) 評論(0)  編輯  收藏 所屬分類: Jetty


          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 亳州市| 彰武县| 泾阳县| 寻乌县| 诸城市| 格尔木市| 东光县| 梧州市| 奎屯市| 沁源县| 南澳县| 太和县| 固始县| 吴忠市| 龙胜| 乌鲁木齐县| 开平市| 宁陵县| 疏勒县| 介休市| 依安县| 通辽市| 慈溪市| 顺义区| 颍上县| 五寨县| 榆中县| 汉寿县| 寿光市| 塔城市| 姚安县| 富顺县| 宁德市| 贵阳市| 阳高县| 蚌埠市| 青神县| 石棉县| 华亭县| 贺兰县| 沙田区|