<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    瘋狂

    STANDING ON THE SHOULDERS OF GIANTS
    posts - 481, comments - 486, trackbacks - 0, articles - 1
      BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

    Jetty

    Posted on 2010-01-29 10:44 瘋狂 閱讀(7885) 評(píng)論(0)  編輯  收藏

    轉(zhuǎn)載自:http://www.cnblogs.com/eafy/archive/2007/10/24/906792.html
    Jetty 是一個(gè)開(kāi)源的servlet容器,它為基于Java的web內(nèi)容,例如JSP和servlet提供運(yùn)行環(huán)境。Jetty是使用Java語(yǔ)言編寫(xiě)的,它的API以一組JAR包的形式發(fā)布。開(kāi)發(fā)人員可以將Jetty容器實(shí)例化成一個(gè)對(duì)象,可以迅速為一些獨(dú)立運(yùn)行(stand-alone)的Java應(yīng)用提供網(wǎng)絡(luò)和web連接。

    本文包括以下內(nèi)容:
    1.        嵌入式Servlet容器有什么意義?
    2.        建立一個(gè)嵌入式的容器: 使用The Jetty API
    3.        將配置從代碼中獨(dú)立出來(lái): XML驅(qū)動(dòng)的配置文件
    4.        可執(zhí)行的JAR包
    5.        結(jié)論
    6.        資源


    如果讓一個(gè)人說(shuō)出一種開(kāi)源的servlet容器,可能他們會(huì)回答Apache Tomcat。但是,Tomcat并不是孤單的,我們還有Jetty。Jetty作為可選的servlet容器只是一個(gè)額外的功能,而它真正出名是因?yàn)樗亲鳛橐粋€(gè)可以嵌入到其他的Java代碼中的servlet容器而設(shè)計(jì)的。這就是說(shuō),開(kāi)發(fā)小組將Jetty作為一組Jar文件提供出來(lái),因此你可以在你自己的代碼中將servlet容器實(shí)例化成一個(gè)對(duì)象并且可以操縱這個(gè)容器對(duì)象。

    Jetty在servlet容器中算不上一個(gè)新面孔;它從1998年就已經(jīng)嶄露頭角。Jetty的發(fā)布遵循了Apache 2.0的開(kāi)源協(xié)議,你可以在免費(fèi)軟件和商業(yè)軟件中使用Jetty而不用支付版稅。

    在本文中,筆者將為你為何需要嵌入式servlet容器提出一點(diǎn)見(jiàn)解,解釋Jetty API的基礎(chǔ),并且展示如何使用XML配置文件來(lái)將Jetty的代碼精簡(jiǎn)到最少。

    本文的示例代碼是在Jetty5.1.10以及Sun JDK 1.5.0_03下測(cè)試的。

    版權(quán)聲明:任何獲得Matrix授權(quán)的網(wǎng)站,轉(zhuǎn)載時(shí)請(qǐng)務(wù)必保留以下作者信息和鏈接
    作者:Ethan McCallum;shenpipi
    原文:http://www.onjava.com/pub/a/onjava/2006/06/14/what-is-jetty.html
    Matrix:http://www.matrix.org.cn/resource/article/44/44588_Jetty.html
    關(guān)鍵字:Jetty

    嵌入式Servlet容器的意義何在?

    在你采用Jetty之前,理智的做法是首先問(wèn)問(wèn)自己:為什么自己的應(yīng)用程序中需要嵌入一個(gè)servlet容器。 吸引我的視線的是Jetty可以為一個(gè)已經(jīng)存在的應(yīng)用程序提供servlet功能的能力。這種能力對(duì)于很多組織都是有用的,包括Java EE應(yīng)用服務(wù)器生產(chǎn)商,軟件測(cè)試人員以及定制軟件生產(chǎn)商。大部分的Java開(kāi)發(fā)人員都可以劃分到這三種情況中。

    首先,考慮要建立自己的Java EE應(yīng)用服務(wù)器這樣一種邊緣情況。根據(jù)規(guī)范,一個(gè)完整的應(yīng)用服務(wù)器必須提供servlet,EJB,以及其他一些功能。你應(yīng)該采用已經(jīng)存在而且測(cè)試過(guò)的組件并且使用Jetty而不是從零開(kāi)始。Apache Geronimo, JBoss, 和ObjectWeb JOnAS這些項(xiàng)目組在建立自己Java EE應(yīng)用服務(wù)器時(shí)也是這樣做的。

    當(dāng)已經(jīng)存在的容器不能滿足需要的時(shí)候,軟件測(cè)試人員會(huì)得益于按照需要來(lái)生成自己的servlet容器。例如,曾經(jīng)有個(gè)同事想要尋找某種方式來(lái)驅(qū)動(dòng)他為web service代碼所寫(xiě)的單元測(cè)試。對(duì)于他的這種情形——幾個(gè)開(kāi)發(fā)人員加上幾個(gè)運(yùn)行在Cruise Control中的自動(dòng)單元測(cè)試——我向他示范了在他的單元測(cè)試組(unit test suites)中如何動(dòng)態(tài)的(on the fly)使用Jetty來(lái)實(shí)例化一個(gè)servlet容器。沒(méi)有多余的腳本,沒(méi)有剩余的文件,只有代碼。

    對(duì)于那些開(kāi)發(fā)Java EE應(yīng)用作為產(chǎn)品的人員來(lái)說(shuō),為什么僅僅提供一個(gè)WAR文件?這樣你為會(huì)容器的規(guī)范而頭疼,同時(shí)也會(huì)增加你的技術(shù)支持的成本。相反的,可以提供給客戶一個(gè)自己具有啟動(dòng),停止以及管理功能的應(yīng)用程序。就連硬件生產(chǎn)商也會(huì)從中受益:Jetty對(duì)于普通的HTTP服務(wù)(沒(méi)有servlet)只需要350k的內(nèi)存,這使得可以將其用在智能設(shè)備中。你可以提供基于web的控制面板并且具有Java web應(yīng)用的所有功能而不用擔(dān)心那些獨(dú)立的容器所帶來(lái)的壓力。

    最后,我敢打賭嵌入式servlet容器最有趣的應(yīng)用會(huì)發(fā)生在那些從來(lái)不編寫(xiě)傳統(tǒng)的基于web應(yīng)用的人身上??梢詫ava EE和HTTP的組合作為一個(gè)C/S結(jié)構(gòu)程序的后臺(tái)??紤]一個(gè)事件驅(qū)動(dòng)的服務(wù),例如(假想的)Message-Driven Bank(onjava上的另外一篇文章中提到),從main()方法啟動(dòng)并且等待到來(lái)的請(qǐng)求,就像Unix中的daemon程序一樣??隙〞?huì)有一些人想要將這個(gè)程序暴露成一種基于用戶的風(fēng)格,例如一個(gè)GUI桌面應(yīng)用,這只是個(gè)時(shí)間問(wèn)題。

    要?jiǎng)?chuàng)建自己的基礎(chǔ)組件,協(xié)議和socket通訊代碼是最令人生厭的,而且會(huì)使人從業(yè)務(wù)邏輯中分心,就更不用說(shuō)將來(lái)可能要調(diào)試的事情了。使用嵌入式的Jetty容器來(lái)將業(yè)務(wù)邏輯通過(guò)HTTP協(xié)議暴露是一個(gè)不錯(cuò)的選擇,它不用對(duì)現(xiàn)有程序作過(guò)多改變。選擇采用Swing,SWT,XUI這些GUI并且將請(qǐng)求包裝成HTTP Post操作,REST,甚至SOAP來(lái)完成這個(gè)回路。與定制的特定于某個(gè)領(lǐng)域的協(xié)議相比,這些通用的協(xié)議可能性能稍差,但是,用不了多久,你就會(huì)從這些已經(jīng)存在的經(jīng)過(guò)實(shí)際檢驗(yàn)的協(xié)議中得到好處并且節(jié)省大量的努力。

    建立一個(gè)嵌入式的容器:使用Jetty API

    希望以上的想法能夠刺激你的胃口讓你嘗試一下嵌入式的servlet容器。示例程序Step1Driver 演示了一個(gè)基于Jetty的簡(jiǎn)單服務(wù)。它創(chuàng)建了一個(gè)servlet容器的實(shí)例,將一個(gè)servlet class映射到一個(gè)URI,并且使用一些URL來(lái)調(diào)用這個(gè)servlet。為了代碼的簡(jiǎn)潔,我犧牲了一些代碼的質(zhì)量。

    Service對(duì)象就是Jetty容器,實(shí)例化出這樣一個(gè)對(duì)象就產(chǎn)生了一個(gè)容器。

    Server service = new Server() ;


    這樣一來(lái),Service對(duì)象就像一個(gè)沒(méi)有門(mén)的賓館:沒(méi)有人能夠進(jìn)入并且使用,所以還是沒(méi)有用的。接下來(lái)的一行代碼設(shè)置容器在localhost,端口7501監(jiān)聽(tīng)。
    service.addListener( "localhost:7501" ) ;


    為了在所有的interface上監(jiān)聽(tīng),不使用主機(jī)名("addListener( ":7501" )")。就像名字暗示的那樣,你可以調(diào)用addListener()多次來(lái)在多個(gè)interface上監(jiān)聽(tīng)。

    注意到示例代碼中維護(hù)了Server對(duì)象的一個(gè)引用,這是將來(lái)要停止容器需要用到的。
    將一個(gè)web應(yīng)用映射到Service是很直觀的:
    service.addWebApplication(
       "/someContextPath" ,
       "/path/to/some.war"
    ) ;


    這個(gè)調(diào)用將處理一個(gè)web應(yīng)用中的web.xml部署描述符(descriptor)來(lái)映射其中的過(guò)濾器servlet和servlet,就像其他容器所做的那樣。第一個(gè)參數(shù)是context path,這個(gè)web應(yīng)用的所有servlet和JSP都會(huì)被映射成相對(duì)于這個(gè)路徑的URI。第二個(gè)參數(shù)是web應(yīng)用本身??梢允且粋€(gè)打包的WAR文件或者目錄格式的web應(yīng)用。再次調(diào)用addWebApplication()可以用來(lái)添加其他的web應(yīng)用。

    注意到Jetty并不需要一個(gè)完整的符合規(guī)范的WAR文件來(lái)部署servlet。如果編寫(xiě)了一個(gè)搭載于HTTP協(xié)議的定制應(yīng)用程序協(xié)議,你可以加載一個(gè)單一的servlet并且將其通過(guò)網(wǎng)絡(luò)提供出去。并沒(méi)有必要使用WAR文件僅僅為了使一個(gè)非web應(yīng)用具有通過(guò)HTTP協(xié)議訪問(wèn)的功能。

    為了映射這種一次性的servlet,通過(guò)在Service對(duì)象上調(diào)用getContext()動(dòng)態(tài)的建立一個(gè)context。這個(gè)示例代碼建立了一個(gè)叫做/embed的context。
    ServletHttpContext ctx = (ServletHttpContext)
       service.getContext( "/embed" ) ;


    如果context不存在地話,調(diào)用getContext()將會(huì)創(chuàng)建一個(gè)新的context
    接下來(lái),調(diào)用addServlet()將一個(gè)servlet類映射到一個(gè)URI
    ctx.addServlet(
       "Simple" , // servlet name
       "/TryThis/*" , // URI mapping pattern
       "sample.SimpleServlet" // class name
    ) ;


    第一個(gè)參數(shù)是該servlet的一個(gè)描述性的名字。第二個(gè)參數(shù)是要映射的路徑,等同于web.xml servlet映射中的<url-pattern>。這個(gè)映射路徑是相對(duì)于context path的,這里是/embed。”/*”表示這個(gè)servlet接收/embed/TryThis這樣一個(gè)URI,同時(shí)它也會(huì)接收所有以此開(kāi)頭的URI,例如/embed/TryThis/123。在使用一個(gè)單一的servlet來(lái)作為一個(gè)大系統(tǒng)的入口的時(shí)候,這種映射方式非常有用。Struts和Axis就是實(shí)際應(yīng)用中使用這樣的映射方式的例子。
    有時(shí)候你可能想讓你的context成為root context,或者說(shuō)“/”,這樣更像一個(gè)普通的HTTP服務(wù)。Jetty通過(guò)Service.setRootWebapp()來(lái)支持此功能。
    service.setRootWebapp(
       "/path/to/another.war"
    ) ;


    唯一的一個(gè)參數(shù)是一個(gè)web應(yīng)用的路徑。
    容器在此時(shí)還是不活動(dòng)的。而且它也沒(méi)有試圖去綁定要監(jiān)聽(tīng)的socket,啟動(dòng)容器需要調(diào)用:
    service.start() ;


    這個(gè)方法會(huì)立即返回,因?yàn)镴etty將服務(wù)在一個(gè)獨(dú)立的線程中運(yùn)行。因此,當(dāng)容器運(yùn)行的時(shí)候,main()可以來(lái)做其他任何事情。
    其余的代碼是使用一組URL來(lái)調(diào)用這個(gè)嵌入式容器。這些調(diào)用確保容器已經(jīng)在運(yùn)行并且servlet按照期望的方式工作。
    關(guān)閉容器就像啟動(dòng)它一樣直觀
    service.stop() ;


    注意最外層try/catch塊中的catch語(yǔ)句。
    {

       service.start() ;
       // ... URL calls to mapped servlet ...
       service.stop() ;

    }catch( Throwable t ){

       System.exit( 1 ) ;

    }


    顯示的調(diào)用System.exit()確保容器在發(fā)生異常的時(shí)候被關(guān)閉。否則,容器會(huì)持續(xù)運(yùn)行因此整個(gè)應(yīng)用程序也不會(huì)退出。
    必須記住Jetty web應(yīng)用并不限于使用代碼來(lái)訪問(wèn)。如果我將service.stop()從剛才的代碼中去掉,那么容器將一直運(yùn)行并且我可以在瀏覽器中調(diào)用servlet,例如
    http://localhost:7501/embed/TryThis/SomeExtraInfo

    你并不一定要完全按照我說(shuō)的去做。這個(gè)示例代碼可以作為一個(gè)Eclipse項(xiàng)目運(yùn)行。而且你也可以寫(xiě)一段shell腳本使其運(yùn)行在Unix/Linux命令行中。在上面兩種情況下,確信Jetty在你的classpath中。

    將配置從代碼中獨(dú)立出來(lái): XML驅(qū)動(dòng)的配置文件

    盡管Jetty的API非常直觀簡(jiǎn)練,但是直接的調(diào)用Jetty API會(huì)將大量的配置信息——端口號(hào),context path,servlet類名——埋藏在代碼之中。Jetty提供了一種基于XML的配置方式來(lái)替代直接調(diào)用API,這樣你就可以將這些配置信息都放在代碼外面而使你的代碼保持清潔。

    Jetty的XML配置文件是基于Java反射的。java.lang.reflect中的類代表了Java中的方法和類,這樣你可以實(shí)例化一個(gè)對(duì)象并且使用方法的名字和參數(shù)類型來(lái)調(diào)用它的方法。這種情況下,Jetty的XML配置文件解析器會(huì)將XML的element和屬性翻譯成反射方法調(diào)用。

    這段節(jié)選自Step2Driver示例類中的代碼是Step1Driver的一個(gè)改良版本。要是使用到了配置文件,就必須有一定的Jetty代碼來(lái)加載它。
    URL serviceConfig = /* load XML file */ ;
       // can use an InputStream or URL

    XmlConfiguration serverFactory =
       new XmlConfiguration( serviceConfig ) ;

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


    不可否認(rèn),這不比Step1Driver示例節(jié)省多少代碼,但是,即使你要添加新的servlet或者web應(yīng)用,Step2Driver的代碼不會(huì)因此而增加。而直接調(diào)用Service和context對(duì)象的方法在配置逐漸增加的情況下會(huì)越來(lái)越差。
    列表1是Step2Driver加載的XML文件。頂層的<Configure> element 的屬性指明了要實(shí)例化那個(gè)類。這里是Jetty Server對(duì)象。
    <!-- 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對(duì)象上調(diào)用的方法。這里要調(diào)用addListener(),如標(biāo)記(2)處,它自己又有一個(gè)子element叫做<Arg>,這指明了方法的參數(shù)。這里我只能傳遞一個(gè)字符串值作為監(jiān)聽(tīng)的地址,而addListener()卻需要接受一個(gè)SocketListener對(duì)象作為參數(shù)。因此,我要使用<New>在標(biāo)記(3)處實(shí)例化一個(gè)新的SocketListener對(duì)象。標(biāo)記2和3處的代碼等同于以下代碼:
    server.addListener(
       new SocketListener( ... )
    ) ;


    為了配置SocketListener自己,必須使用一個(gè)<Call>來(lái)調(diào)用它的setHost()方法,既然這個(gè)方法遵循了JavaBean的命名規(guī)則,示例代碼因此使用了<Set> element(4)作為一種快捷方式。在后臺(tái),Jetty給set中name屬性所指定的屬性賦值,并且決定調(diào)用什么方法,這里是setHost()

    setHost()的參數(shù)這里沒(méi)有顯示給出,而是使用了<SystemProperty>來(lái)從系統(tǒng)屬性中來(lái)獲取參數(shù)的值,這里從系統(tǒng)參數(shù)service.listen.host 和 service.listen.port。如果系統(tǒng)屬性沒(méi)有定義,你可以使用default來(lái)指定一個(gè)默認(rèn)值。這里,4和5等同于以下調(diào)用:
       socketListener.setHost(
          System.getProperty(
             "service.listen.host" ,
             "localhost"
          )
      ) ;


    最后注意標(biāo)記6處的<Call> element位于調(diào)用getContext方法的<Call>中。內(nèi)部的<Call>是作用在外部的<Call>的返回的對(duì)象上的,這里,調(diào)用的是getServlet()返回的context上的addServlet()方法:
    server.getContext().addServlet( ... ) ;


    Jetty 小組的英明在于這個(gè)XML配置文件的進(jìn)一步深入處理:我們可以注意到列表1中所有的Jetty特定的調(diào)用都是element和屬性的值,而不是名字,這就意味著XML配置文件可以被用在任何類上,而不僅僅是Jetty的類中。根據(jù)你的應(yīng)用程序的編寫(xiě)方式,你可以全部使用Jetty的XML配置文件來(lái)配置。

    可執(zhí)行JAR包

    如果你使用Jetty的XML來(lái)配置你的應(yīng)用,你需要使用大量的重復(fù)的代碼來(lái)加載你的config文件并且運(yùn)行你的應(yīng)用。不過(guò)你可以使用Jetty的可執(zhí)行的start.jar來(lái)為你加載文件,這會(huì)讓你節(jié)省更多的代碼。

    例如,你可以使用以下的命令行來(lái)加載Step2Driver中的Jetty服務(wù)。
    CLASSPATH= ...various Jetty JARs...
    java \
       -Djetty.class.path=${CLASSPATH} \
       -jar <jetty install path>/start.jar \
       standalone.xml


    注意到這個(gè)命令僅僅加載xml文件來(lái)建立容器和監(jiān)聽(tīng)器,因此,它并不會(huì)調(diào)用示例代碼中用來(lái)測(cè)試URL的代碼。

    結(jié)論
    一個(gè)嵌入式的Jetty servlet容器可以讓你的web使用Java應(yīng)用而不用打包成正式的web應(yīng)用的形式。這提供了多種可能性,讓Jetty成為你的工具箱中的一個(gè)多才多藝的幫手。
    當(dāng)然,我這里所寫(xiě)的東西并不能包含Jetty的所有內(nèi)容。我建議你去訪問(wèn)Jetty的網(wǎng)站來(lái)獲取更多的文檔和示例代碼。

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


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 一级女人18片毛片免费视频| 久久久久亚洲精品日久生情| 免费看国产精品麻豆| 成人免费无码大片a毛片| 无人影院手机版在线观看免费 | 亚洲精品在线网站| 亚洲男人的天堂在线播放| 亚洲免费视频在线观看| 亚洲无限乱码一二三四区| 亚洲欧洲日产国产最新| 色天使亚洲综合在线观看| 亚洲色一区二区三区四区| 亚洲s码欧洲m码吹潮| 精品视频免费在线| 男女拍拍拍免费视频网站| 久久这里只精品国产免费10| 亚欧免费一级毛片| 黄色成人免费网站| 青青青青青青久久久免费观看| 国产一卡二卡≡卡四卡免费乱码 | 国产高清不卡免费在线| 我要看免费的毛片| 亚洲A∨精品一区二区三区| 亚洲综合av永久无码精品一区二区| 亚洲日韩激情无码一区| 精品无码一区二区三区亚洲桃色 | 亚洲精品无码久久不卡| 亚洲国产一二三精品无码| 精品亚洲成a人片在线观看少妇 | 久久久久国产亚洲AV麻豆 | 性做久久久久免费观看| 亚洲不卡无码av中文字幕| 欧洲亚洲国产清在高| 亚洲婷婷在线视频| 亚洲精品无码久久久久YW| 一级日本高清视频免费观看| 18女人水真多免费高清毛片| 超pen个人视频国产免费观看| 亚洲无码高清在线观看| 亚洲精品人成电影网| 国产成人亚洲毛片|