原文:https://thinkwon.blog.csdn.ne...前端
Tomcat 服務器Apache軟件基金會項目中的一個核心項目,是一個免費的開放源代碼的Web 應用服務器,屬於輕量級應用服務器,在中小型系統和併發訪問用戶不是不少的場合下被廣泛使用,是開發和調試JSP 程序的首選。java
<Service name="Catalina"> <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
下面,咱們先大體瞭解Tomcat Connector的三種運行模式。web
BIO:同步並阻塞 一個線程處理一個請求。缺點:併發量高時,線程數較多,浪費資源。Tomcat7或如下,在Linux系統中默認使用這種方式。
配製項:protocol=」HTTP/1.1」面試
NIO:同步非阻塞IOapache
利用Java的異步IO處理,能夠經過少許的線程處理大量的請求,能夠複用同一個線程處理多個connection(多路複用)。segmentfault
Tomcat8在Linux系統中默認使用這種方式。設計模式
Tomcat7必須修改Connector配置來啓動。瀏覽器
配製項:protocol=」org.apache.coyote.http11.Http11NioProtocol」
備註:咱們經常使用的Jetty,Mina,ZooKeeper等都是基於java nio實現.tomcat
APR:即Apache Portable Runtime,從操做系統層面解決io阻塞問題。AIO方式,異步非阻塞IO(Java NIO2又叫AIO) 主要與NIO的區別主要是操做系統的底層區別.能夠作個比喻:比做快遞,NIO就是網購後要本身到官網查下快遞是否已經到了(多是屢次),而後本身去取快遞;AIO就是快遞員送貨上門了(不用關注快遞進度)。服務器
配製項:protocol=」org.apache.coyote.http11.Http11AprProtocol」
備註:需在本地服務器安裝APR庫。Tomcat7或Tomcat8在Win7或以上的系統中啓動默認使用這種方式。Linux若是安裝了apr和native,Tomcat直接啓動就支持apr。
在Tomcat中部署Web應用的方式主要有以下幾種:
當容器啓動時,會讀取在webapps目錄下全部的web應用中的web.xml文件,而後對 xml文件進行解析,並讀取servlet註冊信息。而後,將每一個應用中註冊的servlet類都進行加載,並經過 反射的方式實例化。(有時候也是在第一次請求時實例化)
在servlet註冊時加上1若是爲正數,則在一開始就實例化,若是不寫或爲負數,則第一次請求實例化。
Tomcat做爲servlet容器,有三種工做模式:
一、獨立的servlet容器,servlet容器是web服務器的一部分;
二、進程內的servlet容器,servlet容器是做爲web服務器的插件和java容器的實現,web服務器插件在內部地址空間打開一個jvm使得java容器在內部得以運行。反應速度快但伸縮性不足;
三、進程外的servlet容器,servlet容器運行於web服務器以外的地址空間,並做爲web服務器的插件和java容器實現的結合。反應時間不如進程內但伸縮性和穩定性比進程內優;
進入Tomcat的請求能夠根據Tomcat的工做模式分爲以下兩類:
Tomcat做爲應用程序服務器:請求來自於前端的web服務器,這多是Apache, IIS, Nginx等;
Tomcat做爲獨立服務器:請求來自於web瀏覽器;
面試時問到Tomcat相關問題的概率並不高,正式由於如此,不少人忽略了對Tomcat相關技能的掌握,下面這一篇文章整理了Tomcat相關的系統架構,介紹了Server、Service、Connector、Container之間的關係,各個模塊的功能,能夠說把這幾個掌握住了,Tomcat相關的面試題你就不會有任何問題了!另外,在面試的時候你還要有意識無心識的往Tomcat這個地方引,就好比說常見的Spring MVC的執行流程,一個URL的完整調用鏈路,這些相關的題目你是能夠往Tomcat處理請求的這個過程去說的!掌握了Tomcat這些技能,面試官必定會佩服你的!
學了本章以後你應該明白的是:
俗話說,站在巨人的肩膀上看世界,通常學習的時候也是先總覽一下總體,而後逐個部分個個擊破,最後造成思路,瞭解具體細節,Tomcat的結構很複雜,可是 Tomcat 很是的模塊化,找到了 Tomcat 最核心的模塊,問題才能夠遊刃而解,瞭解了 Tomcat 的總體架構對之後深刻了解 Tomcat 來講相當重要!
先上一張Tomcat的頂層結構圖(圖A),以下:
Tomcat中最頂層的容器是Server,表明着整個服務器,從上圖中能夠看出,一個Server能夠包含至少一個Service,便可以包含多個Service,用於具體提供服務。
Service主要包含兩個部分:Connector和Container。從上圖中能夠看出 Tomcat 的心臟就是這兩個組件,他們的做用以下:
一個Tomcat中只有一個Server,一個Server能夠包含多個Service,一個Service只有一個Container,可是能夠有多個Connectors,這是由於一個服務能夠有多個鏈接,如同時提供Http和Https連接,也能夠提供向相同協議不一樣端口的鏈接,示意圖以下(Engine、Host、Context下面會說到):
多個 Connector 和一個 Container 就造成了一個 Service,有了 Service 就能夠對外提供服務了,可是 Service 還要一個生存的環境,必需要有人可以給她生命、掌握其生死大權,那就非 Server 莫屬了!因此整個 Tomcat 的生命週期由 Server 控制。
另外,上述的包含關係或者說是父子關係,均可以在tomcat的conf目錄下的server.xml配置文件中看出,下圖是刪除了註釋內容以後的一個完整的server.xml配置文件(Tomcat版本爲8.0)
詳細的配置文件內容能夠到Tomcat官網查看:Tomcat配置文件
上邊的配置文件,還能夠經過下邊的一張結構圖更清楚的理解:
Server標籤設置的端口號爲8005,shutdown=」SHUTDOWN」 ,表示在8005端口監聽「SHUTDOWN」命令,若是接收到了就會關閉Tomcat。一個Server有一個Service,固然還能夠進行配置,一個Service有多個Connector,Service左邊的內容都屬於Container的,Service下邊是Connector。
Tomcat中只有一個Server,一個Server能夠有多個Service,一個Service能夠有多個Connector和一個Container;
Server掌管着整個Tomcat的生死大權;
Service 是對外提供服務的;
Connector用於接受請求並將請求封裝成Request和Response來具體處理;
Container用於封裝和管理Servlet,以及具體處理request請求;
知道了整個Tomcat頂層的分層架構和各個組件之間的關係以及做用,對於絕大多數的開發人員來講Server和Service對咱們來講確實很遠,而咱們開發中絕大部分進行配置的內容是屬於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!
Connector架構分析
Connector用於接受請求並將請求封裝成Request和Response,而後交給Container進行處理,Container處理完以後在交給Connector返回給客戶端。
所以,咱們能夠把Connector分爲四個方面進行理解:
Connector如何接受請求的?
如何將請求封裝成Request和Response的?
封裝完以後的Request和Response如何交給Container進行處理的?
Container處理完以後如何交給Connector並返回給客戶端的?
首先看一下Connector的結構圖(圖B),以下所示:
Connector就是使用ProtocolHandler來處理請求的,不一樣的ProtocolHandler表明不一樣的鏈接類型,好比:Http11Protocol使用的是普通Socket來鏈接的,Http11NioProtocol使用的是NioSocket來鏈接的。
其中ProtocolHandler由包含了三個部件:Endpoint、Processor、Adapter。
Endpoint用來處理底層Socket的網絡鏈接,Processor用於將Endpoint接收到的Socket封裝成Request,Adapter用於將Request交給Container進行具體的處理。
Endpoint因爲是處理底層的Socket網絡鏈接,所以Endpoint是用來實現TCP/IP協議的,而Processor用來實現HTTP協議的,Adapter將請求適配到Servlet容器進行具體的處理。
Endpoint的抽象實現AbstractEndpoint裏面定義的Acceptor和AsyncTimeout兩個內部類和一個Handler接口。Acceptor用於監聽請求,AsyncTimeout用於檢查異步Request的超時,Handler用於處理接收到的Socket,在內部調用Processor進行處理。
至此,咱們應該很輕鬆的回答1,2,3的問題了,可是4仍是不知道,那麼咱們就來看一下Container是如何進行處理的以及處理完以後是如何將處理完的結果返回給Connector的?
Container用於封裝和管理Servlet,以及具體處理Request請求,在Container內部包含了4個子容器,結構圖以下(圖C):
4個子容器的做用分別是:
Engine:引擎,用來管理多個站點,一個Service最多隻能有一個Engine;
Host:表明一個站點,也能夠叫虛擬主機,經過配置Host就能夠添加站點;
Context:表明一個應用程序,對應着平時開發的一套程序,或者一個WEB-INF目錄以及下面的web.xml文件;
Wrapper:每一Wrapper封裝着一個Servlet;
下面找一個Tomcat的文件目錄對照一下,以下圖所示:
Context和Host的區別是Context表示一個應用,咱們的Tomcat中默認的配置下webapps下的每個文件夾目錄都是一個Context,其中ROOT目錄中存放着主應用,其餘目錄存放着子應用,而整個webapps就是一個Host站點。
咱們訪問應用Context的時候,若是是ROOT下的則直接使用域名就能夠訪問,例如:www.baidu.com,若是是Host(webapps)下的其餘應用,則可使用www.baidu.com/docs進行訪問,固然默認指定的根應用(ROOT)是能夠進行設定的,只不過Host站點下默認的主應用是ROOT目錄下的。
看到這裏咱們知道Container是什麼,可是仍是不知道Container是如何進行請求處理的以及處理完以後是如何將處理完的結果返回給Connector的?別急!下邊就開始探討一下Container是如何進行處理的!
Container處理請求是使用Pipeline-Valve管道來處理的!(Valve是閥門之意)
Pipeline-Valve是責任鏈模式,責任鏈模式是指在一個請求處理的過程當中有不少處理者依次對請求進行處理,每一個處理者負責作本身相應的處理,處理完以後將處理後的結果返回,再讓下一個處理者繼續處理。
可是!Pipeline-Valve使用的責任鏈模式和普通的責任鏈模式有些不一樣!區別主要有如下兩點:
每一個Pipeline都有特定的Valve,並且是在管道的最後一個執行,這個Valve叫作BaseValve,BaseValve是不可刪除的;
在上層容器的管道的BaseValve中會調用下層容器的管道。
咱們知道Container包含四個子容器,而這四個子容器對應的BaseValve分別在:StandardEngineValve、StandardHostValve、StandardContextValve、StandardWrapperValve。
Pipeline的處理流程圖以下(圖D):
Connector在接收到請求後會首先調用最頂層容器的Pipeline來處理,這裏的最頂層容器的Pipeline就是EnginePipeline(Engine的管道);
在Engine的管道中依次會執行EngineValve一、EngineValve2等等,最後會執行StandardEngineValve,在StandardEngineValve中會調用Host管道,而後再依次執行Host的HostValve一、HostValve2等,最後在執行StandardHostValve,而後再依次調用Context的管道和Wrapper的管道,最後執行到StandardWrapperValve。
當執行到StandardWrapperValve的時候,會在StandardWrapperValve中建立FilterChain,並調用其doFilter方法來處理請求,這個FilterChain包含着咱們配置的與請求相匹配的Filter和Servlet,其doFilter方法會依次調用全部的Filter的doFilter方法和Servlet的service方法,這樣請求就獲得了處理!
當全部的Pipeline-Valve都執行完以後,而且處理完了具體的請求,這個時候就能夠將返回的結果交給Connector了,Connector在經過Socket的方式將結果返回給客戶端。
至此,咱們已經對Tomcat的總體架構有了大體的瞭解,從圖A、B、C、D能夠看出來每個組件的基本要素和做用。咱們在腦海裏應該有一個大概的輪廓了!若是你面試的時候,讓你簡單的聊一下Tomcat,上面的內容你能脫口而出嗎?當你可以脫口而出的時候,面試官必定會對你另眼相看的!
若有錯誤或其它問題,歡迎小夥伴留言評論、指正。若有幫助,歡迎點贊+轉發分享。
歡迎你們關注民工哥的公衆號:民工哥技術之路