從Servlet到Tomcat再到Jetty

咱們直到Servlet是處理每一個HTTP請求的最小單元,而這些Servlet又被web容器所管理,不一樣的web容器有不一樣的特性和應用特色,好比常見的web 容器Tomcat和Jetty。前端

(另外咱們還知道一些高性能web框架好比netty,和tomcat的區別是什麼呢?web

  • tomcat是基於HTTP協議的web容器,經常使用來作前端請求的服務器,也支持NIO模式;
  • 而netty是一個網絡框架,能夠基於HTTP/TCP/UTP,也能夠自定義協議,自主開發不一樣的web服務器,以知足不一樣的場景需求;)

 

本文旨在探究web容器組織管理servlet的機制,和web容器怎麼去處理不一樣的線程請求。設計模式

 

 

 

從Tomcat啓動流程提及

Tomcat的系統結構:tomcat

 

 

 

 

 

 

Tomcat是一系列層級容器組成的web容器,其中最頂層的容器是Server,表明着整個服務器,從上圖中能夠看出,一個Server能夠包含至少一個Service,用於具體提供服務;服務器

 

Service容器包含的來個主要組件是ConnetctorContainer;這是Tomcat最重要的兩個組件:網絡

 

  1. Connector用於處理連接相關的事情,並提供Socket與Request和Response相關的轉化;
  2. Container用於封裝和管理Servlet,以及具體處理Request請求;

 

這種設計模式是網絡I/O常見的設計,爲了可以併發處理大量鏈接,通常會採起一個線程方式監聽客戶端請求;另外一個線程採用NIO的形式select已經接收到數據的channel信道,處理請求,這樣的形式;多線程

Tomcat7提供了三種Connector:Java Blocking Connector,Java Nio Blocking Connector,APR/native Connector。架構

  • Java Blocking Connector是Tomcat7默認的網絡鏈接處理方式,其處理模型爲一個或多個線程(Acceptor)接收TCP鏈接,每一個鏈接的請求都會交由單獨的線程(Worker)處理。
  • Java Nio Blocking Connector是Tomcat8默認的處理方式。爲了不鏈接過多(尤爲是keepalive的鏈接會阻塞worker線程)形成的線程資源浪費,它在接收網絡鏈接的線程(Acceptor)和請求處理線程(Worker)之間增長了Poller事件隊列,每當有IO就緒事件都會放入Poller隊列,Poller線程會不斷消費隊列裏的事件,交由Worker線程處理。
  • APR/native Connector,APR即Apache Portable Runtime Libraries,使用了native代碼來優化網絡請求的處理。

 

在容器等級中的最底層就是Context容器,負責直接管理Servlet,一個Context對應一個Web工程;併發

 

 Tomcat的啓動邏輯是基於觀察者設計的,先來看看啓動的時序圖:app

 

 

 

容器的配置屬性由web.xml制定;

 

 

Tomcat處理一次http請求的時序圖:

 

 

 

 

有了一個總體的瞭解後,讓咱們再來看看Tomcat是如何分發請求,以及處理多用戶同時請求和管理多級容器的;

 

 

Tomcat是如何分發請求

 

 Tomcat中使用Connector處理多線程的鏈接請求:

 先看看Connector的主要類圖:其中處理Socket的是HttpProcessor

 

 容器的整體設計: Container是容器的父接口,全部子容器都必須實現這個接口,其中用到的設計模式是責任鏈模式

Engine -> Host -> Context -> Wrapper 這四個容器是個分別包含的父子關係(參見上幾個圖)

四個容器的關係類圖:

 

 

來看看Jetty 

 

Jetty相較於Tomcat更加輕便,雖然架構更加簡單,可是看起來可並不輕鬆。Spring是設計初衷是用來管理應用中的實例Bean,於是是基於Bean的架構;Jetty則更傾向於流程和組件的管理,採用了基於handler的架構。handler的嵌套和鏈式結構,LifeCycle和doStart、doHandler模式無不印證了這點

 

Jetty基礎架構: 

 

 

 

 

 Jetty與Tomcat的區別

 

Jetty 的架構從前面的分析可知,它的全部組件都是基於 Handler 來實現,固然它也支持 JMX。可是主要的功能擴展均可以用 Handler 來實現。能夠說 Jetty 是面向 Handler 的架構,就像 Spring 是面向 Bean 的架構,iBATIS 是面向 statement 同樣,而 Tomcat 是以多級容器構建起來的,它們的架構設計必然都有一個「元神」,全部以這個「元神「構建的其它組件都是肉身。

從設計模板角度來看 Handler 的設計實際上就是一個責任鏈模式,接口類 HandlerCollection 能夠幫助開發者構建一個鏈,而另外一個接口類 ScopeHandler 能夠幫助你控制這個鏈的訪問順序。另一個用到的設計模板就是觀察者模式,用這個設計模式控制了整個 Jetty 的生命週期,只要繼承了 LifeCycle 接口,你的對象就能夠交給 Jetty 來統一管理了。因此擴展 Jetty 很是簡單,也很容易讓人理解,總體架構上的簡單也帶來了無比的好處,Jetty 能夠很容易被擴展和裁剪。

相比之下,Tomcat 要臃腫不少,Tomcat 的總體設計上很複雜,前面說了 Tomcat 的核心是它的容器的設計,從 Server 到 Service 再到 engine 等 container 容器。做爲一個應用服務器這樣設計無口厚非,容器的分層設計也是爲了更好的擴展,這是這種擴展的方式是將應用服務器的內部結構暴露給外部使用者,使得若是想擴展 Tomcat,開發人員必需要首先了解 Tomcat 的總體設計結構,而後才能知道如何按照它的規範來作擴展。這樣無形就增長了對 Tomcat 的學習成本。不只僅是容器,實際上 Tomcat 也有基於責任鏈的設計方式,像串聯 Pipeline 的 Vavle 設計也是與 Jetty 的 Handler 相似的方式。要本身實現一個 Vavle 與寫一個 Handler 的難度不相上下。表面上看,Tomcat 的功能要比 Jetty 強大,由於 Tomcat 已經幫你作了不少工做了,而 Jetty 只告訴,你能怎麼作,如何作,有你去實現。

單純比較 Tomcat 與 Jetty 的性能意義不是很大,只能說在某種使用場景下,它表現的各有差別。由於它們面向的使用場景不盡相同。從架構上來看 Tomcat 在處理少數很是繁忙的鏈接上更有優點,也就是說鏈接的生命週期若是短的話,Tomcat 的整體性能更高。

而 Jetty 恰好相反,Jetty 能夠同時處理大量鏈接並且能夠長時間保持這些鏈接。例如像一些 web 聊天應用很是適合用 Jetty 作服務器,像淘寶的 web 旺旺就是用 Jetty 做爲 Servlet 引擎。

另外因爲 Jetty 的架構很是簡單,做爲服務器它能夠按需加載組件,這樣不須要的組件能夠去掉,這樣無形能夠減小服務器自己的內存開銷,處理一次請求也是能夠減小產生的臨時對象,這樣性能也會提升。另外 Jetty 默認使用的是 NIO 技術在處理 I/O 請求上更佔優點,Tomcat 默認使用的是 BIO,在處理靜態資源時,Tomcat 的性能不如 Jetty。

相關文章
相關標籤/搜索