1. 程式人生 > >Java架構師必讀原始碼之Tomcat

Java架構師必讀原始碼之Tomcat

Tomcat的結構雖然很複雜,但Tomcat非常模組化,找到Tomcat最核心的模組,問題才可以解決,熟悉Tomcat的整體架構對深入瞭解Tomcat來說至關重要!

一、Tomcat頂層架構

先上一張Tomcat的頂層結構圖,如下:

Tomcat中最頂層的容器是Server,代表著整個伺服器,從上圖中可以看出,一個Server可以包含至少一個Service,用於具體提供服務。

Service主要包含兩個部分:Connector和Container。從上圖中可以看出 Tomcat 的心臟就是這兩個元件,他們的作用如下:

Tomcat中只有一個Server,一個Server可以包含多個Service,一個Service只有一個Container,但是可以有多個Connectors,這是因為一個服務可以有多個連線,如同時提供Http和Https連結,也可以提供向相同協議不同埠的連線,示意圖如下:

多個Connector 和一個 Container就形成了一個 Service,有了 Service 就可以對外提供服務了,但是 Service 還要一個生存的環境,必須要有人能夠給它生命、掌握其生死大權,那就非 Server 莫屬了!所以整個 Tomcat 的生命週期由 Server 控制。

另外,上述的包含關係或者說是父子關係,都可以在tomcat的conf目錄下的server.xml配置檔案中看出,下圖是刪除了註釋內容之後的一個完整的server.xml配置檔案(Tomcat版本為8.0)

詳細配置檔案

檔案內容可以到Tomcat官網檢視:http://tomcat.apache.org/tomcat-8.0-doc/index.html上邊的配置檔案,還可以通過下邊的一張結構圖更清楚地理解:

Sevr標籤設定的埠號為8005,shutdown=”SHUTDOWN” ,表示在8005埠監聽“SHUTDOWN”命令,如果接收到了就會關閉Tomcat。一個Server有一個Service,當然還可以進行配置,一個Service有多個,Service左邊的內容都屬於Container的,Service下邊是Connector。

二、Tomcat頂層架構小結:

1、Tomcat中只有一個Server,一個Server可以有多個Service,一個Service可以有多個Connector和一個Container;

2、Server掌管著整個Tomcat的生死大權;

3、Service 是對外提供服務的;

4、Connector用於接受請求並將請求封裝成Request和Response來具體處理;

5、Container用於封裝和管理Servlet,以及具體處理request請求;

知道整個Tomcat頂層的分層架構和各個元件之間的關係以及作用,對於絕大多數的開發人員來說Server和Service確實很遠,而我們開發中絕大部分進行配置的內容是屬於Connector和Container的,所以接下來介紹一下Connector和Container。

三、Connector和Container的微妙關係

由上述內容我們大致可以知道一個請求傳送到Tomcat之後,首先經過Service然後會交給我們的Connector,Connector用於接收請求並將接收的請求封裝為Request和Response來具體處理,Request和Response封裝完之後再交由Container進行處理,Container處理完請求之後再返回給Connector,最後在由Connector通過Socket將處理的結果返回給客戶端,這樣整個請求的就處理完了!

Connector最底層使用的是Socket來進行連線的,Request和Response是按照HTTP協議來封裝的,所以Connector同時需要實現TCP/IP協議和HTTP協議!

Tomcat既然處理請求,那麼肯定需要先接收到這個請求,接收請求這個東西我們首先就需要看一下Connector!

為了幫助大家少走彎路,我請BAT大廠工作的同事總結出一套技術視訊,涵蓋Java工程化、高效能及分散式、效能調優、Spring、Netty原始碼分析和大資料等知識點,想要了解詳情的可以加入Java後端技術群:697579751,免費的大型網際網路Java技術視訊分享給大家。其實我自己也比較喜歡技術,群裡有一些阿里大牛,也有一線網際網路的資深HR,最近在面試的朋友或者在找工作的可以進來看看!

四、Connector架構分析

Connector用於接受請求並將請求封裝成Request和Response,然後交給Container進行處理,Container處理完之後在交給Connector返回給客戶端。

因此,我們可以把Connector分為四個方面進行理解:

首先看一下Connector的結構圖(圖B),如下所示:

Connetr就是使用ProtocolHandler來處理請求的,不同的ProtocolHandler代表不同的連線型別,比如:Http11Protocol使用的是普通Socket來連線的,Http11NioProtocol使用的是NioSocket來連線的。

其中ProtocolHandler由包含了三個部件:Endpoint、Processor、Adapter。

1、Endpoint用來處理底層Socket的網路連線,Processor用於將Endpoint接收到的Socket封裝成Request,Adapter用於將Request交給Container進行具體的處理。

2、Endpoint由於是處理底層的Socket網路連線,因此Endpoint是用來實現TCP/IP協議的,而Processor用來實現HTTP協議的,Adapter將請求適配到Servlet容器進行具體的處理。

3、Endpoint的抽象實現AbstractEndpoint裡面定義的Acceptor和AsyncTimeout兩個內部類和一個Handler介面。Acceptor用於監聽請求,AsyncTimeout用於檢查非同步Request的超時,Handler用於處理接收到的Socket,在內部呼叫Processor進行處理。

至此,我們應該很輕鬆的回答(1)(2)(3)的問題了,但是(4)還是不知道,那麼我們就來看一下Container是如何進行處理的以及處理完之後是如何將處理完的結果返回給Connector的?

五、Container架構分析

Container用於封裝和管理Servlet,以及具體處理Request請求,在Connector內部包含了4個子容器,結構圖如下(圖C):

4個子容器的作用分別是:

下面找一個Tomcat的檔案目錄對照一下,如下圖所示:

Context和Host的區別是Context表示一個應用,我們的Tomcat中預設的配置下webapps下的每一個資料夾目錄都是一個Context,其中ROOT目錄中存放著主應用,其他目錄存放著子應用,而整個webapps就是一個Host站點。

我們訪問應用Context的時候,如果是ROOT下的則直接使用域名就可以訪問,例如:www.ledouit.com,如果是Host(webapps)下的其他應用,則可以使用www.ledouit.com/docs進行訪問,當然預設指定的根應用(ROOT)是可以進行設定的,只不過Host站點下預設的主營用是ROOT目錄下的。

看到這裡我們知道Container是什麼,但是還是不知道Container是如何進行處理的以及處理完之後是如何將處理完的結果返回給Connector的?別急!下邊就開始探討一下Container是如何進行處理的!

六、Container如何處理請求的

Container處理請求是使用Pipeline-Valve管道來處理的!

Pipeline-Valve是責任鏈模式,責任鏈模式是指在一個請求處理的過程中有很多處理者依次對請求進行處理,每個處理者負責做自己相應的處理,處理完之後將處理後的請求返回,再讓下一個處理著繼續處理。

但是!Pipeline-alve使用的責任鏈模式和普通的責任鏈模式有些不同!區別主要有以下兩點:

我們知道Containr含四個子容器,而這四個子容器對應的BaseValve分別在:StandardEngineValve、StandardHostValve、StandardContextValve、StandardWrapperValve。

Pipeline的處理流程圖如下(圖D):

1、Connector接到請求後會首先呼叫最頂層容器的Pipeline來處理,這裡的最頂層容器的Pipeline就是EnginePipeline(Engine的管道);

2、在Engine的管道中依次會執行EngineValve1、EngineValve2等等,最後會執行StandardEngineValve,在StandardEngineValve中會呼叫Host管道,然後再依次執行Host的HostValve1、HostValve2等,最後在執行StandardHostValve,然後再依次呼叫Context的管道和Wrapper的管道,最後執行到StandardWrapperValve。

3、當執行到StandardWrapperValve的時候,會在StandardWrapperValve中建立FilterChain,並呼叫其doFilter方法來處理請求,這個FilterChain包含著我們配置的與請求相匹配的Filter和Servlet,其doFilter方法會依次呼叫所有的Filter的doFilter方法和Servlet的service方法,這樣請求就得到了處理!

4、當所有的Pipeline-Valve都執行完之後,並且處理完了具體的請求,這個時候就可以將返回的結果交給Connector了,Connector在通過Socket的方式將結果返回給客戶端。

總結

至此,我們已經對Tomcat的整體架構有了大致的瞭解,從圖A、B、C、D可以看出來每一個元件的基本要素和作用。我們在腦海裡應該有一個大概的輪廓了!如果你面試的時候,讓你簡單的聊一下Tomcat,上面的內容你能脫口而出嗎?當你能夠脫口而出的時候,面試官一定會對你刮目相看的!

為了幫助大家少走彎路,我請BAT大廠工作的同事總結出一套技術視訊,涵蓋Java工程化、高效能及分散式、效能調優、Spring、Netty原始碼分析和大資料等知識點,想要了解詳情的可以加入Java後端技術群:697-57-9751,免費的大型網際網路Java技術視訊分享給大家。其實我自己也比較喜歡技術,群裡有一些阿里大牛,也有一線網際網路的資深HR,最近在面試的朋友或者在找工作的可以進來看看!