<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 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

    Jetty

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

    轉載自:http://www.cnblogs.com/eafy/archive/2007/10/24/906792.html
    Jetty 是一個開源的servlet容器,它為基于Java的web內容,例如JSP和servlet提供運行環境。Jetty是使用Java語言編寫的,它的API以一組JAR包的形式發布。開發人員可以將Jetty容器實例化成一個對象,可以迅速為一些獨立運行(stand-alone)的Java應用提供網絡和web連接。

    本文包括以下內容:
    1.        嵌入式Servlet容器有什么意義?
    2.        建立一個嵌入式的容器: 使用The Jetty API
    3.        將配置從代碼中獨立出來: XML驅動的配置文件
    4.        可執行的JAR包
    5.        結論
    6.        資源


    如果讓一個人說出一種開源的servlet容器,可能他們會回答Apache Tomcat。但是,Tomcat并不是孤單的,我們還有Jetty。Jetty作為可選的servlet容器只是一個額外的功能,而它真正出名是因為它是作為一個可以嵌入到其他的Java代碼中的servlet容器而設計的。這就是說,開發小組將Jetty作為一組Jar文件提供出來,因此你可以在你自己的代碼中將servlet容器實例化成一個對象并且可以操縱這個容器對象。

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

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

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

    版權聲明:任何獲得Matrix授權的網站,轉載時請務必保留以下作者信息和鏈接
    作者: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
    關鍵字:Jetty

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

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

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

    當已經存在的容器不能滿足需要的時候,軟件測試人員會得益于按照需要來生成自己的servlet容器。例如,曾經有個同事想要尋找某種方式來驅動他為web service代碼所寫的單元測試。對于他的這種情形——幾個開發人員加上幾個運行在Cruise Control中的自動單元測試——我向他示范了在他的單元測試組(unit test suites)中如何動態的(on the fly)使用Jetty來實例化一個servlet容器。沒有多余的腳本,沒有剩余的文件,只有代碼。

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

    最后,我敢打賭嵌入式servlet容器最有趣的應用會發生在那些從來不編寫傳統的基于web應用的人身上。可以將Java EE和HTTP的組合作為一個C/S結構程序的后臺。考慮一個事件驅動的服務,例如(假想的)Message-Driven Bank(onjava上的另外一篇文章中提到),從main()方法啟動并且等待到來的請求,就像Unix中的daemon程序一樣。肯定會有一些人想要將這個程序暴露成一種基于用戶的風格,例如一個GUI桌面應用,這只是個時間問題。

    要創建自己的基礎組件,協議和socket通訊代碼是最令人生厭的,而且會使人從業務邏輯中分心,就更不用說將來可能要調試的事情了。使用嵌入式的Jetty容器來將業務邏輯通過HTTP協議暴露是一個不錯的選擇,它不用對現有程序作過多改變。選擇采用Swing,SWT,XUI這些GUI并且將請求包裝成HTTP Post操作,REST,甚至SOAP來完成這個回路。與定制的特定于某個領域的協議相比,這些通用的協議可能性能稍差,但是,用不了多久,你就會從這些已經存在的經過實際檢驗的協議中得到好處并且節省大量的努力。

    建立一個嵌入式的容器:使用Jetty API

    希望以上的想法能夠刺激你的胃口讓你嘗試一下嵌入式的servlet容器。示例程序Step1Driver 演示了一個基于Jetty的簡單服務。它創建了一個servlet容器的實例,將一個servlet class映射到一個URI,并且使用一些URL來調用這個servlet。為了代碼的簡潔,我犧牲了一些代碼的質量。

    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/*" , // URI mapping pattern
       "sample.SimpleServlet" // class name
    ) ;


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


    唯一的一個參數是一個web應用的路徑。
    容器在此時還是不活動的。而且它也沒有試圖去綁定要監聽的socket,啟動容器需要調用:
    service.start() ;


    這個方法會立即返回,因為Jetty將服務在一個獨立的線程中運行。因此,當容器運行的時候,main()可以來做其他任何事情。
    其余的代碼是使用一組URL來調用這個嵌入式容器。這些調用確保容器已經在運行并且servlet按照期望的方式工作。
    關閉容器就像啟動它一樣直觀
    service.stop() ;


    注意最外層try/catch塊中的catch語句。
    {

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

    }catch( Throwable t ){

       System.exit( 1 ) ;

    }


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

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

    將配置從代碼中獨立出來: XML驅動的配置文件

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

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

    這段節選自Step2Driver示例類中的代碼是Step1Driver的一個改良版本。要是使用到了配置文件,就必須有一定的Jetty代碼來加載它。
    URL serviceConfig = /* load XML file */ ;
       // 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的代碼。

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

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


    網站導航:
     
    主站蜘蛛池模板: 亚洲成a人片在线观看播放| 91亚洲导航深夜福利| 国产av无码专区亚洲av毛片搜| av大片在线无码免费| 亚洲精品不卡视频| 最新黄色免费网站| 亚洲精品在线免费看| 永久免费在线观看视频| 亚洲天堂男人影院| 免费看美女让人桶尿口| 免费无码又爽又黄又刺激网站| 亚洲国产a级视频| 天堂在线免费观看| 亚洲AV无码不卡无码| 天天影视色香欲综合免费| 久久亚洲国产最新网站| 国产成人高清精品免费软件| 美女被免费视频网站a| 亚洲色婷婷一区二区三区| 国产精成人品日日拍夜夜免费| 亚洲狠狠狠一区二区三区| 国内大片在线免费看| 国产精品自拍亚洲| 亚洲精品中文字幕无码蜜桃| 50岁老女人的毛片免费观看| 亚洲国产成人久久一区二区三区 | 亚洲AV男人的天堂在线观看| 国产精品麻豆免费版| 国产成人无码区免费内射一片色欲| 精品亚洲成a人片在线观看| 手机在线免费视频| a一级毛片免费高清在线| 亚洲精品中文字幕无码AV| 国产免费av片在线无码免费看| 国产精品免费视频观看拍拍| 亚洲高清资源在线观看| 免费a在线观看播放| 在线观看免费av网站| 免费精品久久久久久中文字幕| 亚洲国产高清人在线| 四虎影视永久免费观看网址|