Tomcat - 理解Tomcat架構設計
前文我們已經介紹了一個簡單的Servlet容器是如何設計出來,我們就可以開始正式學習Tomcat了,在學習開始,我們有必要站在高點去看看Tomcat的架構設計。@pdai
準備知識
一些準備知識點。
Tomcat和Catalina是什麼關係?
Tomcat的前身為Catalina,Catalina又是一個輕量級的Servlet容器
Tomcat的前身為Catalina,Catalina又是一個輕量級的Servlet容器。在美國,catalina是一個很美的小島。所以Tomcat作者的寓意可能是想把Tomcat設計成一個優雅美麗且輕量級的web伺服器。Tomcat從4.x版本開始除了作為支援Servlet的容器外,額外加入了很多的功能,比如:jsp、el、naming等等,所以說Tomcat不僅僅是Catalina。
什麼是Servlet?
所謂Servlet,其實就是Sun為了讓Java能實現動態可互動的網頁,從而進入Web程式設計領域而制定的一套標準!
在網際網路興起之初,當時的Sun公司(後面被Oracle收購)已然看到了這次機遇,於是設計出了Applet來對Web應用的支援。不過事實卻並不是預期那麼得好,Sun悲催地發現Applet並沒有給業界帶來多大的影響。經過反思,Sun就想既然機遇出現了,市場前景也非常不錯,總不能白白放棄了呀,怎麼辦呢?於是又投入精力去搞一套規範出來,這時Servlet誕生了!
一個Servlet主要做下面三件事情:
- 建立並填充Request物件,包括:URI、引數、method、請求頭資訊、請求體資訊等
- 建立Response物件
- 執行業務邏輯,將結果通過Response的輸出流輸出到客戶端
Servlet沒有main方法,所以,如果要執行,則需要在一個容器裡面才能執行,這個容器就是為了支援Servlet的功能而存在,Tomcat其實就是一個Servlet容器的實現。
Tomcat 總結架構
下圖應該是網上能找的最好的關於Tomcat的架構圖了, 我們來看下它的構成:
從元件的角度看
-
Server: 表示伺服器,它提供了一種優雅的方式來啟動和停止整個系統,不必單獨啟停聯結器和容器;它是Tomcat構成的頂級構成元素,所有一切均包含在Server中;
-
Service: 表示服務,Server可以執行多個服務。比如一個Tomcat裡面可執行訂單服務、支付服務、使用者服務等等;Server的實現類StandardServer可以包含一個到多個Services, Service的實現類為StandardService呼叫了容器(Container)介面,其實是呼叫了Servlet Engine(引擎),而且StandardService類中也指明瞭該Service歸屬的Server;
-
Container: 表示容器,可以看做Servlet容器;引擎(Engine)、主機(Host)、上下文(Context)和Wraper均繼承自Container介面,所以它們都是容器。
- Engine -- 引擎
- Host -- 主機
- Context -- 上下文
- Wrapper -- 包裝器
-
Connector: 表示聯結器, 它將Service和Container連線起來,首先它需要註冊到一個Service,它的作用就是把來自客戶端的請求轉發到Container(容器),這就是它為什麼稱作聯結器, 它支援的協議如下:
- 支援AJP協議
- 支援Http協議
- 支援Https協議
-
Service內部還有各種支撐元件,下面簡單羅列一下這些元件
- Manager -- 管理器,用於管理會話Session
- Logger -- 日誌器,用於管理日誌
- Loader -- 載入器,和類載入有關,只會開放給Context所使用
- Pipeline -- 管道元件,配合Valve實現過濾器功能
- Valve -- 閥門元件,配合Pipeline實現過濾器功能
- Realm -- 認證授權元件
從web.xml配置和模組對應角度
上述模組的理解不是孤立的,它直接對映為Tomcat的web.xml配置,讓我們聯絡起來看
從一個完整請求的角度來看
通過一個完整的HTTP請求,我們還需要把它貫穿起來
假設來自客戶的請求為:http://localhost:8080/test/index.jsp 請求被髮送到本機埠8080,被在那裡偵聽的Coyote HTTP/1.1 Connector,然後
- Connector把該請求交給它所在的Service的Engine來處理,並等待Engine的回應
- Engine獲得請求localhost:8080/test/index.jsp,匹配它所有虛擬主機Host
- Engine匹配到名為localhost的Host(即使匹配不到也把請求交給該Host處理,因為該Host被定義為該Engine的預設主機)
- localhost Host獲得請求/test/index.jsp,匹配它所擁有的所有Context
- Host匹配到路徑為/test的Context(如果匹配不到就把該請求交給路徑名為""的Context去處理)
- path="/test"的Context獲得請求/index.jsp,在它的mapping table中尋找對應的servlet
- Context匹配到URL PATTERN為*.jsp的servlet,對應於JspServlet類,構造HttpServletRequest物件和HttpServletResponse物件,作為引數呼叫JspServlet的doGet或doPost方法
- Context把執行完了之後的HttpServletResponse物件返回給Host
- Host把HttpServletResponse物件返回給Engine
- Engine把HttpServletResponse物件返回給Connector
- Connector把HttpServletResponse物件返回給客戶browser
從原始碼的設計角度看
從功能的角度將Tomcat原始碼分成5個子模組,分別是:
-
Jsper模: 這個子模組負責jsp頁面的解析、jsp屬性的驗證,同時也負責將jsp頁面動態轉換為java程式碼並編譯成class檔案。在Tomcat原始碼中,凡是屬於org.apache.jasper包及其子包中的原始碼都屬於這個子模組;
-
Servlet和Jsp模組: 這個子模組的原始碼屬於javax.servlet包及其子包,如我們非常熟悉的javax.servlet.Servlet介面、javax.servet.http.HttpServlet類及javax.servlet.jsp.HttpJspPage就位於這個子模組中;
-
Catalina模組: 這個子模組包含了所有以org.apache.catalina開頭的java原始碼。該子模組的任務是規範了Tomcat的總體架構,定義了Server、Service、Host、Connector、Context、Session及Cluster等關鍵元件及這些元件的實現,這個子模組大量運用了Composite設計模式。同時也規範了Catalina的啟動及停止等事件的執行流程。從程式碼閱讀的角度看,這個子模組應該是我們閱讀和學習的重點。
-
Connector模組: 如果說上面三個子模組實現了Tomcat應用伺服器的話,那麼這個子模組就是Web伺服器的實現。所謂聯結器(Connector)就是一個連線客戶和應用伺服器的橋樑,它接收使用者的請求,並把使用者請求包裝成標準的Http請求(包含協議名稱,請求頭Head,請求方法是Get還是Post等等)。同時,這個子模組還按照標準的Http協議,負責給客戶端傳送響應頁面,比如在請求頁面未發現時,connector就會給客戶端瀏覽器傳送標準的Http 404錯誤響應頁面。
-
Resource模組: 這個子模組包含一些資原始檔,如Server.xml及Web.xml配置檔案。嚴格說來,這個子模組不包含java原始碼,但是它還是Tomcat編譯執行所必需的。
從後續深入理解的角度
我們看完上述元件結構後,後續應該重點從哪些角度深入理解Tomcat呢?
- 基於元件的架構
我們知道組成Tomcat的是各種各樣的元件,每個元件各司其職,元件與元件之間有明確的職責劃分,同時元件與元件之間又通過一定的聯絡相互通訊。Tomcat整體就是一個個元件的堆砌!
- 基於JMX
我們在後續閱讀Tomcat原始碼的時候,會發現程式碼裡充斥著大量的類似於下面的程式碼。
Registry.getRegistry(null, null).invoke(mbeans, "init", false);
Registry.getRegistry(null, null).invoke(mbeans, "start", false);
而這實際上就是通過JMX來管理相應物件的程式碼。這兒我們不會詳細講述什麼是JMX,我們只是簡單地說明一下JMX的概念,參考JMX百度百科。
JMX(Java Management Extensions,即Java管理擴充套件)是一個為應用程式、裝置、系統等植入管理功能的框架。JMX可以跨越一系列異構作業系統平臺、系統體系結構和網路傳輸協議,靈活的開發無縫整合的系統、網路和服務管理應用。
- 基於生命週期
如果我們查閱各個元件的原始碼,會發現絕大多陣列件實現了Lifecycle介面,這也就是我們所說的基於生命週期。生命週期的各個階段的觸發又是基於事件的方式。
更多文章
相關文章
- Tomcat - 如何設計一個簡單的web容器
- 在學習Tomcat前,很多人先入為主的對它的認知是巨複雜的;所以第一步,在學習它之前,要打破這種觀念,我們通過學習如何設計一個最基本的web容器來看它需要考慮什麼;進而在真正學習Tomcat時,多把重點放在它的頂層設計上,而不是某一塊程式碼上, 思路永遠比具體實現重要的多。
- Tomcat - 理解Tomcat架構設計
- 前文我們已經介紹了一個簡單的Servlet容器是如何設計出來,我們就可以開始正式學習Tomcat了,在學習開始,我們有必要站在高點去看看Tomcat的架構設計。
- Tomcat - 原始碼分析準備和分析入口
- 上文我們介紹了Tomcat的架構設計,接下來我們便可以下載原始碼以及尋找原始碼入口了。
- Tomcat - 啟動過程:初始化和啟動流程
- 在有了Tomcat架構設計和原始碼入口以後,我們便可以開始真正讀原始碼了。
- Tomcat - 啟動過程:類載入機制詳解
- 上文我們講了Tomcat在初始化時會初始化classLoader。本文將具體分析Tomcat的類載入機制,特別是區別於傳統的
雙親委派模型
的載入機制。
- 上文我們講了Tomcat在初始化時會初始化classLoader。本文將具體分析Tomcat的類載入機制,特別是區別於傳統的
- Tomcat - 啟動過程:Catalina的載入
- 通過前兩篇文章,我們知道了Tomcat的類載入機制和整體的元件載入流程;我們也知道通過Bootstrap初始化的catalinaClassLoader載入了Catalina,那麼進而引入了一個問題就是Catalina是如何載入的呢?載入了什麼呢?本文將帶你進一步分析。
- Tomcat - 元件生命週期管理:LifeCycle
- 上文中,我們已經知道Catalina初始化了Server(它呼叫了 Server 類的 init 和 start 方法來啟動 Tomcat);你會發現Server是Tomcat的配置檔案server.xml的頂層元素,那這個階段其實我們已經進入到Tomcat內部元件的詳解;這時候有一個問題,這麼多元件是如何管理它的生命週期的呢?
- Tomcat - 元件擴充管理:JMX和MBean
- 我們在前文中講Lifecycle以及元件,怎麼會突然講JMX和MBean呢?本文通過承接上文Lifecycle講Tomcat基於JMX的實現。
- Tomcat - 事件的監聽機制:觀察者模式
- 本文承接上文中Lifecycle中實現,引出Tomcat的監聽機制。
- Tomcat - Server的設計和實現: StandardServer
- 基於前面的幾篇文章,我們終於可以總體上梳理Server的具體實現了,這裡體現在StandardServer具體的功能實現上。
- Tomcat - Service的設計和實現: StandardService
- 上文講了Server的具體實現了,本文主要講Service的設計和實現;我們從上文其實已經知道Server中包含多個service了。
- Tomcat - 執行緒池的設計與實現:StandardThreadExecutor
- 上文中我們研究了下Service的設計和實現,StandardService中包含Executor的呼叫;這個比較好理解,Tomcat需要併發處理使用者的請求,自然而言就想到執行緒池,那麼Tomcat中執行緒池(Executor)具體是如何實現的?本文帶你繼續深度解析。
- Tomcat - Request請求處理: Container設計
- 在理解了Server,Service和Executor後,我們可以進入Request處理環節了。我們知道客戶端是可以發起多個請求的,Tomcat也是可以支援多個webapp的,有多個上下文,且一個webapp中可以有多個Servlet...等等,那麼Tomcat是如何設計元件來支撐請求處理的呢?本節文將介紹Tomcat的Container設計。
- Tomcat - Container容器之Engine:StandardEngine
- 上文已經知道Container的整體結構和設計,其中Engine其實就是Servlet Engine,負責處理request的頂層容器。
- Tomcat - Container的管道機制:責任鏈模式
- 上文中介紹了Engine的設計,其中有Pipline相關內容沒有介紹,本文將向你闡述Tomcat的管道機制以及它要解決的問題。
- Tomcat - Request請求處理過程:Connector
- 本文主要介紹request請求的處理過程。