溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Jetty與Tomcat哪個(gè)更好

發(fā)布時(shí)間:2021-12-31 16:37:11 來(lái)源:億速云 閱讀:197 作者:iii 欄目:服務(wù)器

這篇文章主要講解了“Jetty與Tomcat哪個(gè)更好”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“Jetty與Tomcat哪個(gè)更好”吧!

Jetty

基本架構(gòu)

Jetty目前的是一個(gè)比較被看好的 Servlet 引擎,它的架構(gòu)比較簡(jiǎn)單,也是一個(gè)可擴(kuò)展性和非常靈活的應(yīng)用服務(wù)器。它有一個(gè)基本數(shù)據(jù)模型,這個(gè)數(shù)據(jù)模型就是  Handler(處理器),所有可以被擴(kuò)展的組件都可以作為一個(gè) Handler,添加到 Server 中,Jetty 就是幫你管理這些 Handler。Jetty  中另外一個(gè)比不可少的組件是 Connector,它負(fù)責(zé)接受客戶端的連接請(qǐng)求,并將請(qǐng)求分配給一個(gè)處理隊(duì)列去執(zhí)行。

下圖是 Jetty 的基本架構(gòu)圖,整個(gè) Jetty 的核心組件由 Server 和 Connector 兩個(gè)組件構(gòu)成,整個(gè) Server 組件是基于  Handler 容器工作的,它類似與 Tomcat 的 Container 容器。

Jetty與Tomcat哪個(gè)更好

圖 1. Jetty 的基本架構(gòu)

Jetty 中還有一些可有可無(wú)的組件,我們可以在它上做擴(kuò)展。如 JMX,我們可以定義一些 Mbean 把它加到 Server 中,當(dāng) Server  啟動(dòng)的時(shí)候,這些 Bean 就會(huì)一起工作。

Jetty與Tomcat哪個(gè)更好

圖 2. Jetty 的主要組件的類圖

從上圖可以看出整個(gè) Jetty 的核心是圍繞著 Server 類來(lái)構(gòu)建,Server 類繼承了 Handler,關(guān)聯(lián)了 Connector 和  Container,Container 是管理 Mbean 的容器。

Jetty 的 Server 的擴(kuò)展主要是實(shí)現(xiàn)一個(gè)個(gè) Handler 并將 Handler 加到 Server 中,Server 中提供了調(diào)用這些  Handler 的訪問(wèn)規(guī)則。

整個(gè) Jetty 的所有組件的生命周期管理是基于觀察者模板設(shè)計(jì),它和 Tomcat 的管理是類似的。

Jetty與Tomcat哪個(gè)更好

圖 3. LifeCycle 的類關(guān)系圖

每個(gè)組件都會(huì)持有一個(gè)觀察者(在這里是 Listener 類,這個(gè)類通常對(duì)應(yīng)到觀察者模式中常用的 Observer 角色,關(guān)于觀察者模式可以參考  《Tomcat系統(tǒng)架構(gòu)與設(shè)計(jì)模式,第2部分:設(shè)計(jì)模式分析》一文中關(guān)于觀察者模式的講解)集合,當(dāng) start、fail 或 stop 等事件觸發(fā)時(shí),這些  Listener 將會(huì)被調(diào)用,這是最簡(jiǎn)單的一種設(shè)計(jì)方式,相比 Tomcat 的 LifeCycle 要簡(jiǎn)單的多。

體系結(jié)構(gòu)

前面所述 Jetty 主要是基于 Handler 來(lái)設(shè)計(jì)的,Handler 的體系結(jié)構(gòu)影響著整個(gè) Jetty 的方方面面。下面總結(jié)了一下 Handler  的種類及作用:

Jetty與Tomcat哪個(gè)更好

圖 4. Handler 的體系結(jié)構(gòu)

Jetty 主要提供了兩種 Handler 類型,一種是 HandlerWrapper,它可以將一個(gè) Handler  委托給另外一個(gè)類去執(zhí)行,如我們要將一個(gè) Handler 加到 Jetty 中,那么就必須將這個(gè) Handler 委托給 Server 去調(diào)用。配合  ScopeHandler 類我們可以攔截 Handler 的執(zhí)行,在調(diào)用 Handler 之前或之后,可以做一些另外的事情,類似于 Tomcat 中的  Valve(閥門(mén));另外一個(gè) Handler 類型是 HandlerCollection,這個(gè) Handler 類可以將多個(gè) Handler  組裝在一起,構(gòu)成一個(gè) Handler 鏈,方便我們做擴(kuò)展。

啟動(dòng)過(guò)程

Jetty 的入口是 Server 類,Server 類啟動(dòng)完成了,就代表 Jetty 能為你提供服務(wù)了。

它到底能提供哪些服務(wù),就要看 Server 類啟動(dòng)時(shí)都調(diào)用了哪些組件的 start 方法。

從 Jetty 的配置文件我們可以發(fā)現(xiàn),配置 Jetty 的過(guò)程就是將那些類配置到 Server 的過(guò)程。下面是 Jetty 的啟動(dòng)時(shí)序圖:

Jetty與Tomcat哪個(gè)更好

圖5. Jetty啟動(dòng)時(shí)序圖

因?yàn)?Jetty 中所有的組件都會(huì)繼承 LifeCycle,所以 Server 的 start 方法調(diào)用就會(huì)調(diào)用所有已經(jīng)注冊(cè)到 Server  的組件,Server 啟動(dòng)其它組件的順序是:

啟動(dòng)設(shè)置到 Server 的 Handler(通常這個(gè) Handler 會(huì)有很多子 Handler,這些 Handler 將組成一個(gè) Handler  鏈,Server 會(huì)依次啟動(dòng)這個(gè)鏈上的所有 Handler);

接著會(huì)啟動(dòng)注冊(cè)在 Server 上 JMX 的 Mbean,讓 Mbean 也一起工作起來(lái);

***會(huì)啟動(dòng) Connector,打開(kāi)端口,接受客戶端請(qǐng)求。

接受請(qǐng)求

Jetty 作為一個(gè)獨(dú)立的 Servlet 引擎可以獨(dú)立提供 Web 服務(wù),但是它也可以與其他 Web  應(yīng)用服務(wù)器集成,所以它可以提供基于兩種協(xié)議工作,一個(gè)是 HTTP,一個(gè)是 AJP 協(xié)議。

如果將 Jetty 集成到 Jboss 或者 Apache,那么就可以讓 Jetty 基于 AJP 模式工作。

下面分別介紹 Jetty 如何基于這兩種協(xié)議工作,以及如何建立連接和接受請(qǐng)求的。

基于 HTTP 協(xié)議工作

如果前端沒(méi)有其它 web 服務(wù)器,那么 Jetty 應(yīng)該是基于 HTTP 協(xié)議工作。也就是當(dāng) Jetty 接收到一個(gè)請(qǐng)求時(shí),必須要按照 HTTP  協(xié)議解析請(qǐng)求來(lái)封裝返回的數(shù)據(jù)。那么 Jetty 是如何接受一個(gè)請(qǐng)求又如何處理這個(gè)請(qǐng)求呢?

我們?cè)O(shè)置 Jetty 的 Connector 實(shí)現(xiàn)類為 org.eclipse.jetty.server.bi.SocketConnector ,讓  Jetty 以 BIO 的方式工作。

  • Jetty 在啟動(dòng)時(shí)將會(huì)創(chuàng)建 BIO 的工作環(huán)境,它會(huì)創(chuàng)建 HttpConnection 類用來(lái)解析和封裝 HTTP1.1 的協(xié)議。

  • ConnectorEndPoint 類負(fù)責(zé)以 BIO 的處理方式處理連接請(qǐng)求;

  • ServerSocket 負(fù)責(zé)建立 socket 連接接受和傳送數(shù)據(jù);

  • Executor 負(fù)責(zé)處理連接的線程池,處理每一個(gè)請(qǐng)求隊(duì)列中的任務(wù);

  • acceptorThread 是監(jiān)聽(tīng)連接請(qǐng)求,一有 socket 連接,它將進(jìn)入下面的處理流程;

當(dāng) socket 被真正執(zhí)行時(shí),HttpConnection 將被調(diào)用,這里定義了如何將請(qǐng)求傳遞到 servlet 容器里,又如何將請(qǐng)求最終路由到目的  servlet。

下圖是 Jetty 啟動(dòng)創(chuàng)建建立連接的時(shí)序圖:

Jetty與Tomcat哪個(gè)更好

圖 6. 建立連接的時(shí)序圖

Jetty 創(chuàng)建接受連接環(huán)境需要三個(gè)步驟:

創(chuàng)建一個(gè)隊(duì)列線程池,用于處理每個(gè)建立連接產(chǎn)生的任務(wù),這個(gè)線程池可以由用戶來(lái)指定,這個(gè)和 Tomcat 是類似的。

創(chuàng)建 ServerSocket,用于準(zhǔn)備接受客戶端的 socket 請(qǐng)求,以及客戶端用來(lái)包裝這個(gè) socket 的一些輔助類。

創(chuàng)建一個(gè)或多個(gè)監(jiān)聽(tīng)線程,用來(lái)監(jiān)聽(tīng)訪問(wèn)端口是否有連接進(jìn)來(lái)。

相比 Tomcat 創(chuàng)建建立連接的環(huán)境,Jetty 的邏輯更加簡(jiǎn)單,牽涉到的類更少,執(zhí)行的代碼量也更少了。

當(dāng)建立連接的環(huán)境已經(jīng)準(zhǔn)備好了,就可以接受 HTTP 請(qǐng)求了,當(dāng) Acceptor 接受到 socket 連接后將轉(zhuǎn)入下圖所示流程執(zhí)行:

Jetty與Tomcat哪個(gè)更好

圖 7. 處理連接時(shí)序圖

Accetptor 線程將會(huì)為這個(gè)請(qǐng)求創(chuàng)建 ConnectorEndPoint。HttpConnection 用來(lái)表示這個(gè)連接是一個(gè) HTTP  協(xié)議的連接,它會(huì)創(chuàng)建 HttpParse 類解析 HTTP 協(xié)議,并且會(huì)創(chuàng)建符合 HTTP 協(xié)議的 Request 和 Response  對(duì)象。接下去就是將這個(gè)線程交給隊(duì)列線程池去執(zhí)行了。

基于 AJP 工作

通常一個(gè) web 站點(diǎn)的后端服務(wù)器不會(huì)將 Java 的應(yīng)用服務(wù)器直接暴露給服務(wù)訪問(wèn)者,而是在應(yīng)用服務(wù)器(如Jboss)的前面再加一個(gè) web 服務(wù)器(如  Apache 或者 nginx),我想這個(gè)原因大家應(yīng)該很容易理解,如做日志分析、負(fù)載均衡、權(quán)限控制、防止惡意請(qǐng)求以及靜態(tài)資源預(yù)加載等等。

下圖是通常的 web 服務(wù)端的架構(gòu)圖:

Jetty與Tomcat哪個(gè)更好

圖 8. Web 服務(wù)端架構(gòu)

這種架構(gòu)下 servlet 引擎就不需要解析和封裝返回的 HTTP 協(xié)議,因?yàn)?HTTP 協(xié)議的解析工作已經(jīng)在 Apache 或 Nginx  服務(wù)器上完成了,Jboss 只要基于更加簡(jiǎn)單的 AJP 協(xié)議工作就行了,這樣能加快請(qǐng)求的響應(yīng)速度。

對(duì)比 HTTP 協(xié)議的時(shí)序圖可以發(fā)現(xiàn),它們的邏輯幾乎是相同的,不同的是替換了一個(gè)類 Ajp13Parserer 而不是  HttpParser,它定義了如何處理 AJP 協(xié)議以及需要哪些類來(lái)配合。

實(shí)際上在 AJP 處理請(qǐng)求相比較 HTTP 時(shí)唯一的不同就是在讀取到 socket 數(shù)據(jù)包時(shí),如何來(lái)轉(zhuǎn)換這個(gè)數(shù)據(jù)包。如果按照 HTTP  協(xié)議的包格式來(lái)解析就是 HttpParser,如果按照 AJP 協(xié)議來(lái)解析就是 Ajp13Parserer。封裝返回的數(shù)據(jù)也是如此。

讓 Jetty 工作在 AJP 協(xié)議下,需要配置 connector 的實(shí)現(xiàn)類為 Ajp13SocketConnector,這個(gè)類繼承了  SocketConnector 類,覆蓋了父類的 newConnection 方法,為的是創(chuàng)建 Ajp13Connection 對(duì)象而不是  HttpConnection。如下圖表示的是 Jetty 創(chuàng)建連接環(huán)境時(shí)序圖:

Jetty與Tomcat哪個(gè)更好

圖9. Jetty 創(chuàng)建連接環(huán)境時(shí)序圖

與 HTTP 方式唯一不同的地方的就是將 SocketConnector 類替換成了 Ajp13SocketConnector。改成  Ajp13SocketConnector 的目的就是可以創(chuàng)建 Ajp13Connection 類,表示當(dāng)前這個(gè)連接使用的是 AJP 協(xié)議,所以需要用  Ajp13Parser 類解析 AJP 協(xié)議,處理連接的邏輯都是一樣的。如下時(shí)序圖所示:

Jetty與Tomcat哪個(gè)更好

基于 NIO 方式工作

前面所描述的 Jetty 建立客戶端連接到處理客戶端的連接都是基于 BIO 的方式,它也支持另外一種 NIO(網(wǎng)絡(luò)接口對(duì)象) 的處理方式,其中 Jetty  的默認(rèn) connector 就是 NIO 方式。

關(guān)于 NIO 的工作原理可以參考 developerworks 上關(guān)于 NIO 的文章,通常 NIO 的工作原型如下:

Selector selector = Selector.open();   ServerSocketChannel ssc = ServerSocketChannel.open();   ssc.configureBlocking( false );   SelectionKey key = ssc.register( selector, SelectionKey.OP_ACCEPT );   ServerSocketChannel ss = (ServerSocketChannel)key.channel();   SocketChannel sc = ss.accept();   sc.configureBlocking( false );   SelectionKey newKey = sc.register( selector, SelectionKey.OP_READ );   Set selectedKeys = selector.selectedKeys();

創(chuàng)建一個(gè) Selector 相當(dāng)于一個(gè)觀察者,打開(kāi)一個(gè) Server 端通道,把這個(gè) server  通道注冊(cè)到觀察者上并且指定監(jiān)聽(tīng)的事件。然后遍歷這個(gè)觀察者觀察到事件,取出感興趣的事件再處理。這里有個(gè)最核心的地方就是,我們不需要為每個(gè)被觀察者創(chuàng)建一個(gè)線程來(lái)監(jiān)控它隨時(shí)發(fā)生的事件。而是把這些被觀察者都注冊(cè)一個(gè)地方統(tǒng)一管理,然后由它把觸發(fā)的事件統(tǒng)一發(fā)送給感興趣的程序模塊。這里的核心是能夠統(tǒng)一的管理每個(gè)被觀察者的事件,所以我們就可以把服務(wù)端上每個(gè)建立的連接傳送和接受數(shù)據(jù)作為一個(gè)事件統(tǒng)一管理,這樣就不必要每個(gè)連接需要一個(gè)線程來(lái)維護(hù)了。

這里需要注意的地方時(shí),很多人認(rèn)為監(jiān)聽(tīng) SelectionKey.OP_ACCEPT 事件就已經(jīng)是非阻塞方式了,其實(shí) Jetty  仍然是用一個(gè)線程來(lái)監(jiān)聽(tīng)客戶端的連接請(qǐng)求,當(dāng)接受到請(qǐng)求后,把這個(gè)請(qǐng)求再注冊(cè)到 Selector  上,然后才是非阻塞方式執(zhí)行。這個(gè)地方還有一個(gè)容易引起誤解的地方是:認(rèn)為 Jetty 以 NIO  方式工作只會(huì)有一個(gè)線程來(lái)處理所有的請(qǐng)求,甚至?xí)J(rèn)為不同用戶會(huì)在服務(wù)端共享一個(gè)線程從而會(huì)導(dǎo)致基于 ThreadLocal 的程序會(huì)出現(xiàn)問(wèn)題,其實(shí)從 Jetty  的源碼中能夠發(fā)現(xiàn),真正共享一個(gè)線程的處理只是在監(jiān)聽(tīng)不同連接的數(shù)據(jù)傳送事件上,比如有多個(gè)連接已經(jīng)建立,傳統(tǒng)方式是當(dāng)沒(méi)有數(shù)據(jù)傳輸時(shí),線程是阻塞的也就是一直在等待下一個(gè)數(shù)據(jù)的到來(lái),而  NIO 的處理方式是只有一個(gè)線程在等待所有連接的數(shù)據(jù)的到來(lái),而當(dāng)某個(gè)連接數(shù)據(jù)到來(lái)時(shí) Jetty  會(huì)把它分配給這個(gè)連接對(duì)應(yīng)的處理線程去處理,所以不同連接的處理線程仍然是獨(dú)立的。

Jetty 的 NIO 處理方式和 Tomcat 的幾乎一樣,唯一不同的地方是在如何把監(jiān)聽(tīng)到事件分配給對(duì)應(yīng)的連接的處理方式。從測(cè)試效果來(lái)看 Jetty 的  NIO 處理方式更加高效。下面是 Jetty 的 NIO 處理時(shí)序圖:

Jetty與Tomcat哪個(gè)更好

處理請(qǐng)求

下面看一下 Jetty 是如何處理一個(gè) HTTP 請(qǐng)求的。

實(shí)際上 Jetty 的工作方式非常簡(jiǎn)單,當(dāng) Jetty 接受到一個(gè)請(qǐng)求時(shí),Jetty 就把這個(gè)請(qǐng)求交給在 Server 中注冊(cè)的代理 Handler  去執(zhí)行,如何執(zhí)行你注冊(cè)的 Handler,同樣由你去規(guī)定,Jetty 要做的就是調(diào)用你注冊(cè)的***個(gè) Handler 的 handle(String  target, Request baseRequest, HttpServletRequest request, HttpServletResponse  response) 方法,接下去要怎么做,完全由你決定。

要能接受一個(gè) web 請(qǐng)求訪問(wèn),首先要?jiǎng)?chuàng)建一個(gè) ContextHandler,如下代碼所示:

Server server = new Server(8080);   ContextHandler context = new ContextHandler();   context.setContextPath("/");   context.setResourceBase(".");   context.setClassLoader(Thread.currentThread().getContextClassLoader());   server.setHandler(context);   context.setHandler(new HelloHandler());   server.start();   server.join();

當(dāng)我們?cè)跒g覽器里敲入 http://localhost:8080 時(shí)的請(qǐng)求將會(huì)代理到 Server 類的 handle 方法,Server 的  handle 的方法將請(qǐng)求代理給 ContextHandler 的 handle 方法,ContextHandler 又調(diào)用 HelloHandler 的  handle 方法。這個(gè)調(diào)用方式是不是和 Servlet 的工作方式類似,在啟動(dòng)之前初始化,然后創(chuàng)建對(duì)象后調(diào)用 Servlet 的 service 方法。在  Servlet 的 API 中我通常也只實(shí)現(xiàn)它的一個(gè)包裝好的類,在 Jetty 中也是如此,雖然 ContextHandler 也只是一個(gè)  Handler,但是這個(gè) Handler 通常是由 Jetty 幫你實(shí)現(xiàn)了,我們一般只要實(shí)現(xiàn)一些我們具體要做的業(yè)務(wù)邏輯有關(guān)的 Handler  就好了,而一些流程性的或某些規(guī)范的 Handler,我們直接用就好了,如下面的關(guān)于 Jetty 支持 Servlet 的規(guī)范的 Handler  就有多種實(shí)現(xiàn),下面是一個(gè)簡(jiǎn)單的 HTTP 請(qǐng)求的流程。

訪問(wèn)一個(gè) Servlet 的代碼:

Server server = new Server();   Connector connector = new SelectChannelConnector();   connector.setPort(8080);   server.setConnectors(new Connector[]{ connector });   ServletContextHandler root = new   ServletContextHandler(null,"/",ServletContextHandler.SESSIONS);   server.setHandler(root);   root.addServlet(new ServletHolder(new   org.eclipse.jetty.embedded.HelloServlet("Hello")),"/");   server.start();   server.join();

創(chuàng)建一個(gè) ServletContextHandler 并給這個(gè) Handler 添加一個(gè) Servlet,這里的 ServletHolder 是  Servlet 的一個(gè)裝飾類,它十分類似于 Tomcat 中的 StandardWrapper。下面是請(qǐng)求這個(gè) Servlet 的時(shí)序圖:

Jetty與Tomcat哪個(gè)更好

圖 12. Jetty 處理請(qǐng)求的時(shí)序圖

上圖可以看出 Jetty 處理請(qǐng)求的過(guò)程就是 Handler 鏈上 handle 方法的執(zhí)行過(guò)程,在這里需要解釋的一點(diǎn)是 ScopeHandler  的處理規(guī)則,ServletContextHandler、SessionHandler 和 ServletHandler 都繼承了  ScopeHandler,那么這三個(gè)類組成一個(gè) Handler  鏈,它們的執(zhí)行規(guī)則是:ServletContextHandler.handle?ServletContextHandler.doScope  ?SessionHandler. doScope?ServletHandler. doScope?ServletContextHandler.  doHandle?SessionHandler. doHandle?ServletHandler. doHandle,它這種機(jī)制使得我們可以在 doScope  做一些額外工作。

與 Jboss 集成

前面介紹了 Jetty 可以基于 AJP 協(xié)議工作,在正常的企業(yè)級(jí)應(yīng)用中,Jetty 作為一個(gè) Servlet 引擎都是基于 AJP  協(xié)議工作的,所以它前面必然有一個(gè)服務(wù)器,通常情況下與 Jboss 集成的可能性非常大,這里介紹一下如何與 Jboss 集成。

Jboss 是基于 JMX 的架構(gòu),那么只要符合 JMX 規(guī)范的系統(tǒng)或框架都可以作為一個(gè)組件加到 Jboss 中,擴(kuò)展 Jboss 的功能。Jetty  作為主要的 Servlet 引擎當(dāng)然支持與 Jboss 集成。具體集成方式如下:

Jetty 作為一個(gè)獨(dú)立的 Servlet 引擎集成到 Jboss 需要繼承 Jboss 的 AbstractWebContainer  類,這個(gè)類實(shí)現(xiàn)的是模板模式,其中有一個(gè)抽象方法需要子類去實(shí)現(xiàn),它是 getDeployer,可以指定創(chuàng)建 web 服務(wù)的 Deployer。Jetty  工程中有個(gè) jetty-jboss 模塊,編譯這個(gè)模塊就會(huì)產(chǎn)生一個(gè) SAR 包,或者可以直接從官網(wǎng)下載一個(gè) SAR 包。解壓后如下圖:

Jetty與Tomcat哪個(gè)更好

圖 13. jboss-jetty 目錄

在 jboss-jetty-6.1.9 目錄下有一個(gè) webdefault.xml 配置文件,這個(gè)文件是 Jetty 的默認(rèn) web.xml 配置,在  META-INF 目錄發(fā)下發(fā)現(xiàn) jboss-service.xml 文件,這個(gè)文件配置了 MBean,如下:

<mbean code="org.jboss.jetty.JettyService"           name="jboss.web:service=WebServer" xmbean-dd="META-INF/webserver-xmbean.xml">

同樣這個(gè) org.jboss.jetty.JettyService 類也是繼成 org.jboss.web.AbstractWebContainer  類,覆蓋了父類的 startService 方法,這個(gè)方法直接調(diào)用 jetty.start 啟動(dòng) Jetty。

與 Tomcat 的比較

Tomcat 和 Jetty 都是作為一個(gè) Servlet 引擎應(yīng)用的比較廣泛,可以將它們比作為中國(guó)與美國(guó)的關(guān)系,雖然 Jetty 正常成長(zhǎng)為一個(gè)優(yōu)秀的  Servlet 引擎,但是目前的 Tomcat 的地位仍然難以撼動(dòng)。相比較來(lái)看,它們都有各自的優(yōu)點(diǎn)與缺點(diǎn)。

Tomcat 經(jīng)過(guò)長(zhǎng)時(shí)間的發(fā)展,它已經(jīng)廣泛的被市場(chǎng)接受和認(rèn)可,相對(duì) Jetty 來(lái)說(shuō) Tomcat 還是比較穩(wěn)定和成熟,尤其在企業(yè)級(jí)應(yīng)用方面,Tomcat  仍然是***選擇。但是隨著 Jetty 的發(fā)展,Jetty 的市場(chǎng)份額也在不斷提高,至于原因就要?dú)w功與 Jetty 的很多優(yōu)點(diǎn)了,而這些優(yōu)點(diǎn)也是因?yàn)?Jetty  在技術(shù)上的優(yōu)勢(shì)體現(xiàn)出來(lái)的。

架構(gòu)比較

從架構(gòu)上來(lái)說(shuō),顯然 Jetty 比 Tomcat 更加簡(jiǎn)單,如果你對(duì) Tomcat 的架構(gòu)還不是很了解的話,建議你先看一下  《Tomcat系統(tǒng)架構(gòu)與設(shè)計(jì)模式》這篇文章。

Jetty 的架構(gòu)從前面的分析可知,它的所有組件都是基于 Handler 來(lái)實(shí)現(xiàn),當(dāng)然它也支持 JMX。但是主要的功能擴(kuò)展都可以用 Handler  來(lái)實(shí)現(xiàn)??梢哉f(shuō) Jetty 是面向 Handler 的架構(gòu),就像 Spring 是面向 Bean 的架構(gòu),iBATIS 是面向 statement 一樣,而  Tomcat 是以多級(jí)容器構(gòu)建起來(lái)的,它們的架構(gòu)設(shè)計(jì)必然都有一個(gè)“元神”,所有以這個(gè)“元神“構(gòu)建的其它組件都是肉身。

從設(shè)計(jì)模板角度來(lái)看,Handler 的設(shè)計(jì)實(shí)際上就是一個(gè)責(zé)任鏈模式,接口類 HandlerCollection 可以幫助開(kāi)發(fā)者構(gòu)建一個(gè)鏈,而另一個(gè)接口類  ScopeHandler 可以幫助你控制這個(gè)鏈的訪問(wèn)順序。另外一個(gè)用到的設(shè)計(jì)模板就是觀察者模式,用這個(gè)設(shè)計(jì)模式控制了整個(gè) Jetty 的生命周期,只要繼承了  LifeCycle 接口,你的對(duì)象就可以交給 Jetty 來(lái)統(tǒng)一管理了。所以擴(kuò)展 Jetty  非常簡(jiǎn)單,也很容易讓人理解,整體架構(gòu)上的簡(jiǎn)單也帶來(lái)了無(wú)比的好處,Jetty 可以很容易被擴(kuò)展和裁剪。

相比之下,Tomcat 要臃腫很多,Tomcat 的整體設(shè)計(jì)上很復(fù)雜,前面說(shuō)了 Tomcat 的核心是它的容器的設(shè)計(jì),從 Server 到 Service  再到 engine 等 container  容器。作為一個(gè)應(yīng)用服務(wù)器這樣設(shè)計(jì)無(wú)口厚非,容器的分層設(shè)計(jì)也是為了更好的擴(kuò)展,只是這種擴(kuò)展方式將應(yīng)用服務(wù)器的內(nèi)部結(jié)構(gòu)暴露給外部使用者,使得如果想擴(kuò)展  Tomcat,開(kāi)發(fā)人員必須要首先了解 Tomcat 的整體設(shè)計(jì)結(jié)構(gòu),然后才能知道如何按照它的規(guī)范來(lái)做擴(kuò)展。這樣無(wú)形就增加了對(duì) Tomcat  的學(xué)習(xí)成本。不僅僅是容器,實(shí)際上 Tomcat 也有基于責(zé)任鏈的設(shè)計(jì)方式,像串聯(lián) Pipeline 的 Vavle 設(shè)計(jì)也是與 Jetty 的 Handler  類似的方式。要自己實(shí)現(xiàn)一個(gè) Vavle 與寫(xiě)一個(gè) Handler 的難度不相上下。表面上看,Tomcat 的功能要比 Jetty 強(qiáng)大,因?yàn)?Tomcat  已經(jīng)幫你做了很多工作了,而 Jetty 只告訴,你能怎么做,如何做,由你去實(shí)現(xiàn)。 打個(gè)比方,就像小孩子學(xué)數(shù)學(xué),Tomcat 告訴你  1+1=2,1+2=3,2+2=4 這個(gè)結(jié)果,然后你可以根據(jù)這個(gè)方式得出 1+1+2=4,你要計(jì)算其它數(shù)必須根據(jù)它給你的公式才能計(jì)算,而 Jetty  是告訴你加減乘除的算法規(guī)則,然后你就可以根據(jù)這個(gè)規(guī)則自己做運(yùn)算了。所以你一旦掌握了 Jetty,Jetty 將變得異常強(qiáng)大。

性能比較

單純比較 Tomcat 與 Jetty 的性能意義不是很大,只能說(shuō)在某種使用場(chǎng)景下,它表現(xiàn)的各有差異。因?yàn)樗鼈兠嫦虻氖褂脠?chǎng)景不盡相同。從架構(gòu)上來(lái)看  Tomcat 在處理少數(shù)非常繁忙的連接上更有優(yōu)勢(shì),也就是說(shuō)連接的生命周期如果短的話,Tomcat 的總體性能更高。

而 Jetty 剛好相反,Jetty 可以同時(shí)處理大量連接而且可以長(zhǎng)時(shí)間保持這些連接。例如像一些 web 聊天應(yīng)用非常適合用 Jetty  做服務(wù)器,像淘寶的 web 旺旺就是用 Jetty 作為 Servlet 引擎。

另外由于 Jetty  的架構(gòu)非常簡(jiǎn)單,作為服務(wù)器它可以按需加載組件,這樣不需要的組件可以去掉,這樣無(wú)形可以減少服務(wù)器本身的內(nèi)存開(kāi)銷,處理一次請(qǐng)求也是可以減少產(chǎn)生的臨時(shí)對(duì)象,這樣性能也會(huì)提高。另外  Jetty 默認(rèn)使用的是 NIO 技術(shù)在處理 I/O 請(qǐng)求上更占優(yōu)勢(shì),Tomcat 默認(rèn)使用的是 BIO,在處理靜態(tài)資源時(shí),Tomcat 的性能不如  Jetty。

特性比較

作為一個(gè)標(biāo)準(zhǔn)的 Servlet 引擎,它們都支持標(biāo)準(zhǔn)的 Servlet 規(guī)范,還有 Java EE 的規(guī)范也都支持,由于 Tomcat  的使用的更加廣泛,它對(duì)這些支持的更加全面一些,有很多特性 Tomcat 都直接集成進(jìn)來(lái)了。但是 Jetty 的應(yīng)變更加快速,這一方面是因?yàn)?Jetty  的開(kāi)發(fā)社區(qū)更加活躍,另一方面也是因?yàn)?Jetty 的修改更加簡(jiǎn)單,它只要把相應(yīng)的組件替換就好了,而 Tomcat 的整體結(jié)構(gòu)上要復(fù)雜很多,修改功能比較緩慢。所以  Tomcat 對(duì)***的 Servlet 規(guī)范的支持總是要比人們預(yù)期的要晚。

感謝各位的閱讀,以上就是“Jetty與Tomcat哪個(gè)更好”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)Jetty與Tomcat哪個(gè)更好這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI