首頁 > Java > java教程 > 主體

深入jetty的使用詳解

黄舟
發布: 2016-12-14 17:33:57
原創
2354 人瀏覽過

簡介: Jetty 是一個用 Java 實作、開源、基於標準的,並且具有豐富功能的 Http 伺服器和 Web 容器,可以免費的用於商業行為。 Jetty 這個計畫成立於 1995 年,現在已經有非常多的成功產品是基於 Jetty,例如 Apache Geromino, JBoss, IBM Tivoli, Cisco SESM 等。 Jetty 可以用來作為一個傳統的 Web 伺服器,也可以作為一個動態的內容伺服器,並且 Jetty 可以非常容易的嵌入到 Java 應用程式當中。

特性簡介

易用性

易用性是Jetty 設計的基本原則,易用性主要體現在以下幾個方面:

1.透過XML 或API 來對Jetty 進行設定;預設為配置可以滿足大部分的需求;
3.將Jetty 嵌入到應用程式當中只需要非常少的程式碼;
可擴充性

在使用了 Ajax 的 Web 2.0 的應用程式中,每個連線需要保持更長的時間,這樣線程和記憶體的消耗量會急劇的增加。這就使得我們擔心整個程式會因為單一元件陷入瓶頸而影響整個程式的效能。但是有了 Jetty:

1.即使在有大量服務請求的情況下,系統的效能也能保持在一個可以接受的狀態。

2.利用 Continuation 機制來處理大量的用戶請求以及時間比較長的連線。
另外 Jetty 設計了非常良好的接口,因此在 Jetty 的某種實作無法滿足使用者的需求時,使用者可以非常方便地對 Jetty 的某些實作進行修改,使得 Jetty 適用於特殊的應用程式的需求。

易嵌入性

Jetty 設計之初就是作為一個優秀的組件來設計的,這也意味著 Jetty 可以非常容易的嵌入到應用程序當中而不需要程序為了使用 Jetty 做修改。從某種程度上,你也可以把 Jetty 理解為一個內嵌的Web伺服器。

------------------------------------------------ --------------------------------

部署應用程式

將自己的應用程式部署到Jetty 上面是非常簡單的,先將開發好的應用程式打成WAR 套件放到Jetty 的Webapps 目錄下面。然後用如下的命令來啟動 Jetty 伺服器:Java –jar start.jar, 在啟動伺服器後。我們就可以訪問我們的應用程式了,Jetty 的預設連接埠是 8080,WAR 的名字也就是我們的應用程式的 Root Context。例如一個典型的 URL 是:http://127.0.0.1:8080/sample/index.jsp 。

------------------------------------------------ --------------------------------

如何將Jetty 嵌入到程式當中

將Jetty 嵌入到程式當中是非常簡單的, 如程式碼1 所示:首先我們建立一個Server 對象, 並設定連接埠為8080,然後為這個Server 物件新增一個預設的 Handler。接著我們用設定檔 jetty.xml 對這個 server 進行設置,最後我們使用方法 server.start() 將 Server 啟動起來就可以了。從這段程式碼可以看出,Jetty 是非常適合用於作為一個元件來嵌入到我們的應用程式當中的,這也是 Jetty 的一個非常重要的特點。

清單 1. 程式碼片段


public class JettyServer {
    public static void main(String[] args) {
        Server server = new Server(8080);
        server.setHandler(new DefaultHandler());
        XmlConfiguration configuration = null;
        try {
            configuration = new XmlConfiguration(
                new FileInputStream("C:/development/Jetty/jetty-6.1.6rc0/etc/jetty.xml"));
        } catch (FileNotFoundException e1) {
            e1.printStackTrace();
        } catch (SAXException e1) {
            e1.printStackTrace();
        } catch (IOException e1) {
            e1.printStackTrace();
        }

        try {    
            configuration.configure(server);
            server.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
登入後複製

接下來我們分析一下 Jetty Server 是如何啟動的。首先我們注意到 Server 類,這個類別實際上繼承了 HttpServer, 當啟動 Jetty 伺服器的時候,就是說,在 Jetty 根目錄下的命令行下如果輸入 java -jar start.jar etc/jetty.xml,注意這裡有一個設定文件 jetty.xml 做為運作參數,這個參數也可以是其它的設定文件,可以是多個 XML 設定文件,其實這個設定檔好比我們使用 Struts 時的 struts-config.xml 文件,將執行 Server 需要用到的元件寫在裡面,例如上一節 HttpServer 的配置所需的元件類別都可以寫在這個設定檔中。依上述方法啟動 Jetty Server 時,就會呼叫 Server 類別裡面的 main 方法,這個入口方法會先建構一個 Server 類別實例(其實也就建構了一個 HttpServer),在創建實例的過程中就會建構 XmlConfiguration 類別的物件來讀取參數設定文件,之後再由這個設定檔產生的 XmlConfiguration 物件來設定這個 Server,設定過程其實是運用了 Java 的反射機制,呼叫 Server 的方法並傳入設定檔中所寫的參數來向這個 Server 新增 HttpListener,HttpContext,HttpHandler,以及 Web Application(對應於我們的 Web 應用)。


--------------------------------------------- ----------------------------------

Jetty 的Continuation 機制

讨论 Jetty 的 Continuation 机制,首先需要提到 Ajax 技术,Ajax 技术是当前开发 Web 应用的非常热门的技术,也是 Web 2.0 的一个重要的组成部分。Ajax 技术中的一个核心对象是 XMLHttpRequest 对象,这个对象支持异步请求,所谓异步请求即是指当客户端发送一个请求到服务器的时候,客户端不必一直等待服务器的响应。这样就不会造成整个页面的刷新,给用户带来更好的体验。而当服务器端响应返回时,客户端利用一个 Javascript 函数对返回值进行处理,以更新页面上的部分元素的值。但很多时候这种异步事件只是在很小一部分的情况下才会发生,那么怎么保证一旦服务器端有了响应之后客户端马上就知道呢,我们有两种方法来解决这个问题,一是让浏览器每隔几秒请求服务器来获得更改,我们称之为轮询。二是服务器维持与浏览器的长时间的连接来传递数据,长连接的技术称之为 Comet。

大家很容易就能发现轮询方式的主要缺点是产生了大量的传输浪费。因为可能大部分向服务器的请求是无效的,也就是说客户端等待发生的事件没有发生,如果有大量的客户端的话,那么这种网络传输的浪费是非常厉害的。特别是对于服务器端很久才更新的应用程序来讲,比如邮件程序,这种浪费就更是巨大了。并且对 Server 端处理请求的能力也相应提高了要求。如果很长时间才向 Server 端发送一次请求的话,那么客户端就不能的得到及时的响应。

如果使用 Comet 技术的话,客户端和服务器端必须保持一个长连接,一般情况下,服务器端每一个 Servlet 都会独占一个线程,这样就会使得服务器端有很多线程同时存在,这在客户端非常多的情况下也会对服务器端的处理能力带来很大的挑战。

Jetty 利用 Java 语言的非堵塞 I/O 技术来处理并发的大量连接。 Jetty 有一个处理长连接的机制:一个被称为 Continuations 的特性。利用 Continuation 机制,Jetty 可以使得一个线程能够用来同时处理多个从客户端发送过来的异步请求,下面我们通过一个简化的聊天程序的服务器端的代码来演示不使用 Continuation 机制和使用 Continuation 的差别。

清单 2. Continuation 机制

public class ChatContinuation extends HttpServlet{

    public void doPost(HttpServletRequest request, HttpServletResponse response){
        postMessage(request, response);
    }

    private void postMessage(HttpServletRequest request, HttpServletResponse response)
    {
        HttpSession session = request.getSession(true);
        People people = (People)session.getAttribute(session.getId());
        if (!people.hasEvent())
        {
            Continuation continuation = 
                ContinuationSupport.getContinuation(request, this);
            people.setContinuation(continuation);
            continuation.suspend(1000);
        }
        people.setContinuation(null);
        people.sendEvent(response);
    }
}
登入後複製

大家注意到,首先获取一个 Continuation 对象,然后把它挂起 1 秒钟,直到超时或者中间被 resume 函数唤醒位置,这里需要解释的是,在调用完 suspend 函数之后,这个线程就可处理其他的请求了,这也就大大提高了程序的并发性,使得长连接能够获得非常好的扩展性。


如果我们不使用 Continuation 机制,那么程序就如 清单 3 所示:

清单 3. 不使用 Continuation 机制

public class Chat extends HttpServlet{
    public void doPost(HttpServletRequest request, HttpServletResponse response){
        postMessage(request, response);
    }

    private void postMessage(HttpServletRequest request, HttpServletResponse response)
    {
        HttpSession session = request.getSession(true);
        People people = (People)session.getAttribute(session.getId());
        while (!people.hasEvent())
        {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        people.setContinuation(null);
        people.sendEvent(response);    
    }
}
登入後複製

大家注意到在等待事件发生的时间里,线程被挂起,直到所等待的事件发生为止,但在等待过程中,这个线程不能处理其他请求,这也就造成了在客户端非常多的情况下服务器的处理能力跟不上的情况。下面我们解释一下 Jetty 的 Continuation 的机制是如何工作的。


为了使用 Continuatins,Jetty 必须配置为使用它的 SelectChannelConnector 处理请求。这个 connector 构建在 java.nio API 之上,允许它维持每个连接开放而不用消耗一个线程。当使用 SelectChannelConnector 时,ContinuationSupport.getContinuation() 提供一个 SelectChannelConnector.RetryContinuation 实例(但是,您必须针对 Continuation 接口编程)。当在 RetryContinuation 上调用 suspend() 时,它抛出一个特殊的运行时异常 -- RetryRequest,该异常传播到 servlet 外并且回溯到 filter 链,最后被 SelectChannelConnector 捕获。但是不会发送一个异常响应给客户端,而是将请求维持在未决 Continuations 队列里,则 HTTP 连接保持开放。这样,用来服务请求的线程返回给 ThreadPool,然后又可以用来服务其他请求。暂停的请求停留在未决 Continuations 队列里直到指定的过期时间,或者在它的 Continuation 上调用 resume() 方法。当任何一个条件触发时,请求会重新提交给 servlet(通过 filter 链)。这样,整个请求被"重播"直到 RetryRequest 异常不再抛出,然后继续按正常情况执行。

--------------------------------------------------------------------------------

Jetty 的安全性

为了防止任何人都有权限去关闭一个已经开启的 Jetty 服务器, 我们可以通过在启动 Jetty 服务器的时候指定参数来进行控制,使得用户必须提供密码才能关闭 Jetty 服务器,启动 Jetty 服务器的命令如下所示:

java -DSTOP.PORT=8079 -DSTOP.KEY=mypassword -jar start.jar
登入後複製

这样,用户在停止 Jetty 服务器的时候,就必须提供密码“mypassword”。

--------------------------------------------------------------------------------

总结

Jetty 是一个非常方便使用的 Web 服务器,它的特点在于非常小,很容易嵌入到我们的应用程序当中,而且针对 Web 2.0 的 Ajax 技术进行了特别的优化,这也使得我们的使用 Ajax 的应用程序可以拥有更好的性能。

以上就是jetty的使用详解,更多相关文章请关注PHP中文网(www.php.cn)!


相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板