深刻理解Tomcat架構

   Tomcat對於web開發人員來講再熟悉不過了,它是由Apache開發的一個免費開源的Web應用服務器。在Web開發時,常常用它構建輕量級的Java Web服務。想要簡單的使用Tomcat是很是容易的,可是想要深刻了解Tomcat體系必需要了解它背後的架構設計。php

   本篇文章對《Tomcat內核設計剖析》這本書的閱讀總結,大概的梳理了一下Tomcat的架構設計、模塊組成。java

   其實從Tomcat配置文件Server.xml的格式就能看出它的結構。web

<?xml version='1.0' encoding='utf-8'?>
<Server>
	<Listener/>
    <GlobalNamingResource>
    	<Resoource/>
    </GlobalNamingResource>
    <Service>
    	<Executor/>
        <Connector/>
        <Engine>
        	<Cluster/>
            <Realm/>
            <Host>
            	<Context/>
            </Host>
        </Engine>
    </Service>
</Server>
複製代碼

Server組件

   Server組件表明整個Tomcat容器,是Tomcat最外層的組件,它包括三個部分:生命週期監聽器,全局命名資源,Service組件數據庫

1.生命週期監聽器

   因爲Tomcat是龐大而複雜的,而且它擁有不少組件,若是這些組件一個一個單獨啓動時很是麻煩的,並且容易遺漏,不易擴展其餘組件。因此Tomcat提供了監聽器方案,在其生命週期的不一樣階段調用監聽器,若是某個組件對於某事件感興趣,只須要實現接口便可緩存

2.全局命名資源

   對應Server.xml配置文件的節點就是<GlobalNamingResource>,在Tomcat初始化時經過Digester框架將其解析成對象,並以樹狀結構存儲,它提供的命名對象經過ResourceLink給全部Web應用訪問使用。如:JNDI中存儲數據庫鏈接池對象。安全

3.監聽關閉命令

   Server組件會開放一個端口用於監聽命令,默認爲8005.當Tomcat接口收到「SHUTDOWN」命令時則會關閉程序。bash

Service組件

   Server組件中能夠包含多個Service組件,Service組件也是Tomcat最外層的組件之一。包含若干Connector組件和Executor組件組合而成,其中不一樣的Connector組件可使用不用的通訊協議,如:HTTP,AJP。服務器

   Executor組件則是Service組件下的線程池,Connector組件能夠經過Executor組件實現線程池共享,默認狀況下使用本身的私有線程池,其餘組件也可使用。此外,Service組件還包含了一個很是重要的Engine組件,Connector組件負責接收客戶端消息,而Engine組件則負責處理客戶端消息。網絡

Connector組件

   Connector主要職責就是接收客戶端鏈接並接收報文,將其解析後裔送給Engine處理。它的組件包括:Protocol組件,Mapper組件,CoyoteAdaptor組件。架構

   Protocol是協議的抽象,它有不一樣的實現,每個實現對應一種通訊協議,其中包括的Endpoint是接收端的抽象,分爲Acceptor專門接收客戶端鏈接的接收器組件和Executor線程池組件,Processor組件是對客戶端請求處理的抽象。

   Mapper是路由組件,它能夠將請求分發到對應的Web應用的某個Servlet上。

   而CoyoteAdaptor組價是一個適配器,它負責將Connector組件和Engine容器適配鏈接起來。

以Http協議來講:

   Protocol組件的HTTP實例則是Http11Protocol和HttpNIOProtocol。由IO模式的不一樣,能夠分爲阻塞模式和非阻塞模式

1.HTTP阻塞模式協議

   HttpProtocol表示阻塞式的HTTP協議通訊,由傳統Socket套接字爲底層實現,它包含JIoEndpoint和Http11Processor組件

  • JIoEndpoint

   ServerSocketFactory根據不一樣的安全層次如HTTP,HTTPS建立ServerSocket對象供Acceptor使用。    鏈接數控制器(LimitLatch)對鏈接數進行計數,來一個請求加一,請求結束後減一。請求數過多時就阻塞請求或拒絕處理。    Socket接收器(Acceptor),監聽某個端口,當有鏈接時就將任務丟給任務執行器。    任務定義器(SocketProcessor),定義好任務處理的統一流程抽象,如:

{
	處理套接字輸出的響應報文;
	鏈接數計數器減一;
	關閉套接字;
}
複製代碼

  任務執行器(Executor),維護一個任務隊列,不斷從任務隊列中取得任務,執行任務定義器定義好的任務。

  • HTTP阻塞處理器(Http11Processor)   Http11Processor提供了對Http協議的通訊處理,將接收到的報文解析成咱們熟知的請求對象,Request和Response,提供一個門面對象供Web應用使用。

2.Http非阻塞模式協議

  Http11NIOProtocol表示非阻塞模式Http協議的通訊,它主要包含NioEndpoint組件和Http11NioProcessor組件。一個鏈接到來時,將被註冊到NioChannel隊列中,由Poller負責檢測通道的讀寫事件,並在建立任務後扔進線程池中。

  BIO模式在接收到一個請求時,將開啓一個線程處理該請求,此時一個線程只能處理一個請求,而且請求並非like發送數據,因爲網絡或業務的一些緣由,服務端並不能馬上接收到數據進行處理,而在等待數據準備的過程當中形成了資源浪費。

  NIO模式克服了這種弊端,它能基於時間在一個線程中同時維護大量鏈接,它將套接字工做交給一個線程,讀寫交給其餘N個線程,在接收請求後,它將請求放入Channel隊列中,用輪詢器不斷檢測通道讀寫事件,若是數據準備好了,可讀後,則將該鏈接交由鏈接池讀寫處理。

  NIO模式,對數據的操做讀寫,即調用基礎的IO操做API依然是阻塞的,只有對網絡IO纔是非阻塞的,在等待數據時是非阻塞的。

  同步非阻塞:同步時對IO來講,非阻塞是處理方式。

Engine容器

  Engine即爲全局引擎容器,它的標準實現爲StandardEngine。其中主要包括組件有Host、AccessLog、Pipeline、Cluster、Realm、LifecycleListener、Log組件。

AccessLog、Log組件,日誌框架

  Tomcat提供了統一的日誌接口Log,並提供了國際化組件,在每一個Java包下面都會存在LocalStrings.properties的不一樣語言版本。而且以Java包爲單位劃分範圍,每一個類若是須要查找消息都到對應的java包下的properties文件中查找。

  還設計了客戶端訪問日誌記錄接口,並提供了不一樣的實現,對持久化方式的不一樣有FileAccessLog,JDBCAccessLog等,還能夠本身實現訪問日誌組件。

Pipeline(管道與閥門)

  在複雜的大型系統中,存在某個對象或數據流須要進行繁雜的邏輯處理,能夠採用管道模式,劃分出每一個小模塊互相獨立且各自負責一段邏輯處理。

  如Request、Response就是這種須要進行繁複加工處理的對象,採用管道在其中設置閥門處理邏輯。在Tomcat中有4個級別的容器分別是 Engine、Host、Context、Wrapper。請求對象將分別由這4個容器處理,在4個容器之間經過管道機制進行傳遞,請求對象先經過Engine管道,經由若干個閥門處理,最後由基礎閥門處理流轉到下一級通道,每一級管道都有一個基礎閥門。

Cluster(集羣)組件

  Tomcat提供了集羣功能,能夠快速的佈置Web集羣應用,而集羣之間的一些通訊則由Cluster組件完成。Cluster組件主要功能是提供會話複製,上下文屬性複製和在集羣下的web應用部署,而且Cluster組件可分爲兩個級別Engine和Host。

  在Cluster組件內部真正負責集羣間通訊的是Tribes組件,它維護着一個集羣內存活主機列表,當Cluster調用發送消息接口時,由Tribes組件將消息發送到集羣中的其餘主機上。

Realm組件

  Realm域其實能夠當作一個包含了用戶及密碼的數據庫,根據用戶角色的不一樣,限制用戶訪問應用的url或資源信息。Realm域是爲了統一web容器資源安全、管理,統一抽象重複認證工做方便web應用資源權限管理開發而提供的一個概念,它支持Engine、Host、Context級別容器的共享。

LifecycleListener

  LifecycleListener便是容器生命週期狀態監聽器。

Host組件

  Host組件是Servlet引擎中虛擬主機的抽象,Engine中能夠包含多個Host容器,而一個Host容器也能夠包含若干個Context容器,Host容器包括的組件有Context容器、AccessLog、Pipeline、Cluster、Realm、HostConfig、Log組件

1.HostConfig

  Host做爲虛擬主機容器,用於放置Context級別容器,而Context其實對應的就是web應用,每一個Tomcat應用都有本身的配置,當Tomcat啓動時,必須把對應web屬性加載進Context中,若是在Tomcat啓動時加載配置,這樣對Context的配置修改不會馬上生效,必須重啓Tomcat。因此Tomcat採用監聽器的方式,當Tomcat啓動時觸發「START_EVENT」事件時執行web應用部署動做。

Context容器

  Context容器對應一個Web應用程序,它包含若干個Wrapper組件、Realm、AccessLog、ErrorPage、Manager、DirContext、安全認證組件、JarScanner、過濾器、NamingResource、Mapper、Pipeline、WebAppLoader、ApplicationContext、InstanceManager、ServletContainerInitializer和Listeners組件。

  • AccessLog、Pipeline、Cluster、Realm,已經介紹過。
  • ErrorPage(錯誤頁面):每一個Context容器都擁有各自的錯誤頁面對象,它能夠在Context標籤下進行配置。
  • Manager(會話管理器):用於Context容器下的會話管理,提供不一樣的實現,有基於內存的,基於文件的持久化,基於JDBC等實現方案,此外針對集羣,還提供了集羣會話管理器,能夠在集羣中同步共享會話。
  • DirContext(目錄上下文):屬於JNDI的標準接口,目的是採用一種簡單的方式訪問整個Web應用包含的文件,因爲web應用文件格式不一樣提供了WARDirContext、FileDirContext兩種實現。
  • JarScanner:顧名思義,它是專門用於掃描Context對於的Web應用的jar包。
  • 過濾器:在web開發中,過濾器是常用的組件之一,它提供了爲某個web應用的全部請求和響應作統一處理的功能。

Wrapper容器

  Wrapper容器對應的就是Servlet,它內部維持了一個Servlet對象或者一個Servlet對象池。通常來講一個Wrapper只有一個Servlet對象,因此全部處理線程都調用同一個Servlet對象,但某個Servlet實現了SingleThreadModel接口也容許多個對象存在。

  request,response對象由Context基礎閥門流轉到Wrapper容器管道後,通過Wrapper管道的多個閥門,最後進入基礎閥門,基礎閥門調用過濾鏈,最後調用Servlet接口的service方法,對於HttpServlet實現來講,在調用service方法後,HttpServlet在service方法內部對Method進行判斷,分別調用doGet、doPost等不一樣方法。

類加載器

  容器最重要的是對於資源的隔離,Tomcat採用自定義的類加載器完成了資源的隔離解決了如下四個問題:

  • 同一個Web服務器內,各web項目之間的java類庫相互隔離
  • 同一個web服務器內,各web項目能夠共享java類庫
  • 服務器不能收web項目影響,因此服務器類庫應該與應用程序隔離
  • 支持熱重載

  使用java類加載器能夠動態加載須要的類,沒有使用到的類不須要加載,能夠節省程序運行內存。在java中咱們用徹底匹配類名來標識一個類,而在JVM中由徹底匹配類名和一個類加載器的實例Id做爲惟一標識。也就是說,同一個虛擬機能夠有兩個包名、類名都相同的類,只要它們由兩個不一樣的類加載器加載。這種特徵爲咱們提供了隔離機制,只要對不一樣的web項目用不一樣的類加載器加載jar包就能夠隔離開資源類庫。而在熱重載的時候,只須要從新建立一個類加載器替換舊的類加載器,而原來的類加載器會被gc回收,就能夠不用重啓Tomcat而從新加載了web應用程序。

Jasper

  Jasper就是JSP解析引擎,Tomcat使用Jasper解析Jsp文件,將之轉化成繼承HttpJspBase的類文件,而後用Eclipse JDT java編譯器或Ant編譯器將java文件編譯成字節碼文件,最後採用類加載器加載字節碼文件。這也是爲何Tomcat第一次訪問jsp文件比較慢的緣由,它須要將jsp編譯成字節碼文件加載運行,在第一次加載完成後,Tomcat將它緩存下來下次就能夠直接使用,而且Tomcat會在後臺線程不斷檢測Jsp文件與編譯後的字節碼文件的最後修改時間是否相同,若是不相同,則表示jsp文件有改動,則須要從新編譯。

總結

  Tomcat是一個十分龐大的項目,其中涉及到方方面面的知識,我根據《Tomcat內核設計剖析》這本書的介紹從宏觀上了解了Tomcat的整體設計,依然某些方面理解起來十分吃力,對於Tomcat架構的細節方面依然須要時間慢慢體會,深刻挖掘。本文也是比較淺顯的作了一下讀書筆記,若是其中有些地方我理解錯誤,歡迎評論指出。

  大概回想了一下,關於Tomcat架構主要就是圍繞Connector和Container組件,一個是接收器,一個是處理容器,而Container組件在Tomcat中沒有顯示標明,它其實就是Engine容器。經過接收器監聽端口鏈接,當有請求到來時,接收器將獲取請求讀取請求報文解析成Request、Response對象,以後交給Engine引擎進行處理,通過一層層處理後,接收器再將Response對象解析成響應報文返回給客戶端。

相關文章
相關標籤/搜索