Tomcat6.0源碼學習--架構概述

Tomcat6是最新版本的web容器,其支持最新版本的servlet2.5jsp2.1。而且Tomcat6架構也是經過重新設計優化過的,所以我們有必要分析一下它的架構過程。顯然,這是一個通過閱讀Tomcat的源代碼及相關文檔,演繹架構的過程。或許有人會說,這不是放馬後炮嗎?!!但我覺得這是自我進步的一個必經步驟,先模仿之,然後才能超越之,畢竟我本凡人。

Tomcat的架構總的來說是分層次的、可插拔的組件架構。分層次是指構成Tomcat的組件不是同一級別的,上層組件可以包含子組件,各個組件有其功能範圍,當一個組件停止服務時,不會影響上層組件的服務。可插拔是指對於組件的添加和刪除並不影響服務器的運行。那麼爲了達到可插拔的組件架構,分層次的組件架構必成爲基礎。

對於任何服務器,即使最簡單的實現,從面向對象設計(OOD)的角度來說,我們都有必要將“服務器”這個概念抽象出來,爲什麼呢?因爲只有有了這個概念,才能談服務器的實例,服務器的功能等等其它概念,此之謂“皮之不存,毛將焉附”。趕巧(其實是我的想法恰好撞上人家的想法),Tomcat也將“服務器”抽象爲java接口org.apache.catalina.Server,顯然Server應該就是最最頂層的組件了。

有了Server這個抽象,很自然的,我們希望它能夠提供對servletjsp支持的功能。但是我們發現這個概念太大了,我們還需再細化。所以別急,我們還有一些事情要解決。服務器要提供服務就必須能夠啓動,當然也應該能夠停止吧,也就是說服務器應該是有生命的,在啓動時初始化必要的資源,而在停止時將其其銷燬掉。好吧,我們把這個也抽象出來,叫做生命週期接口,tomcat 實現爲org.apache.catalina.Lifecycle.如上所述我們知道Lifecycle需要完成的工作了。

publicvoid start() throws LifecycleException;

publicvoid stop() throws LifecycleException;

接下來我們分析服務器如何來處理客戶端的請求,一般的我們會在瀏覽器中輸入如下格式的請求,http://192.168.8.221:8080/explorer/loginInit.do。對於服務器來說,要想處理這個請求,就必須監聽指定的端口8080,當有TCP的請求包來時,建立Socket連接,分析並解析之,然後給客戶端返回響應。在這個過程中,我們發現,其實包含了倆個功能點,即監聽並接受請求和處理請求。那麼我們能否將這倆個功能給抽象出來呢?Tomcat告訴我們,可以。是的,Tomcat將“監聽並接收請求”抽象爲org.apache.catalina.connector.Connector類,負責接受請求;將“處理請求”抽象爲“容器” org.apache.catalina.Container,負責處理Connector傳遞過來的請求。

Ok,到此,我們分析構建的簡單服務器模型出來了,ServerConnector組件和Container組件結合提供web服務。

Tomcat6.0源碼學習--架構概述 - Dinstone - Dinstone 的技術博客

2

有了這個模型後,要實現一個簡單的Server已經很簡單了,但是在實現Container時,我們還是要做很多事情,如當來請求,我們怎麼知道該請求對應得虛擬主機,以及請求的那個應用,應該交給那個servlet對象來處理?這樣看來,Container還是太大了,需要細化。根據Servlet規範,我們知道,servlet屬於某個應用,且有上下文環境,Container要根據應用上下文環境初始化servlet,然後根據servlet映射調用servletservice方法。在這裏“應用上下文環境”的概念很重要,Tomcat將其抽象爲org.apache.catalina.ContextContext繼承了Container接口。對於虛擬主機,Tomcat將其抽象爲org.apache.catalina.HostHost繼承了Container接口。

好了,有了這些概念,我們再回顧一下請求的處理過程:瀏覽器發出請求,Connector接受請求,將請求交由Container處理,Container查找請求對應的Host並將請求傳遞給它,Host拿到請求後查找相應的應用上下文環境,準備servlet環境並調用service方法。

現在,我們的服務器模型變成了如圖3所示了。

Tomcat6.0源碼學習--架構概述 - Dinstone - Dinstone 的技術博客

3

但是在Tomcat的實現體系中還有一個Engine的接口,Engine也繼承了Container接口,那麼這個接口什麼用呢?設計Engine的目的有倆個目的,一,當希望使用攔截器查看(過濾或預處理)每個請求時,Engine是個很好的攔截點。二,當希望多個虛擬Host共享一個HttpConnector時,Engine是個很好的門面。所以,Engine接口是作爲頂級Container組件來設計的,其作用相當於一個Container的門面。有了Engine,請求的處理過程變爲:瀏覽器發出請求,Connector接受請求,將請求交由Container(這裏是Engine)處理,ContainerEngine來擔當)查找請求對應的Host並將請求傳遞給它,Host拿到請求後查找相應的應用上下文環境,準備servlet環境並調用service方法。再看看服務器的模型,如圖4.

Tomcat6.0源碼學習--架構概述 - Dinstone - Dinstone 的技術博客

4

到目前,我們碰到的組件類型有ConnectorContainer,其實,這也就是Tomcat的核心組件。如圖4,一組Connector和一個Container有機的組合在一起構成Server,就可以提供服務了,對於Tomcat來說,主要是提供Servlet服務,那麼也就是說Tomcat服務器也可以提供其它服務了?是的,Tomcat將“一組Connector和一個Container有機的組合”抽象爲“服務”接口org.apache.catalina.Service,然而,這些服務實例彼此獨立,僅僅共享JVM的基礎設施,如系統類路徑。

進一步的,我們得到了服務器的框架模型,如圖5.

Tomcat6.0源碼學習--架構概述 - Dinstone - Dinstone 的技術博客

5

    由圖5,我們知道,對於Tomcat服務器來說,除了Server代表它自己以外,其它組件都是功能組件,都有其職責範圍。Service爲最頂層的組件,可以添加ConnectorContainer組件。EngineContainer的最頂層組件,可以添加Host組件,但不能添加父組件。Host組件的父組件是EngineHost下面包含有Context組件。

    接下來看看標準的Tomcat體系結構,如圖6.

Tomcat6.0源碼學習--架構概述 - Dinstone - Dinstone 的技術博客

6

比較圖5和圖6.我們發現,還有很多輔助組件沒有抽象出來。當然,隨着需求的一步步加深,我的分析也會一步步深入,這些個組件也會慢慢浮出水面。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章