參考自:https://blog.csdn.net/sunyunjie361/article/details/58588033
組件介紹:
Tomcat 最重要的是兩個組件是:Connector(連接器) 和 Container(容器/集裝箱),Connector 組件是可以被替換,這樣可以提供給服務器設計者更多的選擇,因為這個組件是如此重要,不僅跟服務器的設計的本身,而且和不同的應用場景也十分相關,所以一個 Container 可以選擇對應多個 Connector。
多個 Connector 和一個 Container 就組成一個 Service,有了 Service 就可以對外提供服務了,但是 Service 還要一個生存的環境, Server 就提供了這樣一個環境。所以整個 Tomcat 的生命周期由 Server 控制。
下面來一層層的看,首先是Server,什么是server呢?
Server
Server 要完成的任務很簡單,就是要能夠提供一個接口讓其它程序能夠訪問到 Service 集合,同時要維護它所包含的所有 Service 的生命周期,包括如何初始化、如何結束服務、如何找到別人要訪問的 Service。還有一些次要的任務,如記錄Service運行日志,維護Session等等。Server包含的組件結構如下:
Service
Service 是在 Connector 和 Container 外面多包一層,把它們組裝在一起,向外面提供服務,一個 Service 可以設置多個 Connector,但是只能有一個 Container 容器。當然Service不僅僅包含這兩個組件, Service 接口的方法列表如下:
Container
Container本意是集裝箱的意思,是一個接口,定義了下屬的各種容器,重要的是Wrapper、Host、Engine、Context等
Engine(引擎)
負責處理來自相關聯的service的所有請求,處理后,將結果返回給service,而connector是作為service與engine的中間媒介出現的。
一個engine下可以配置一個默認主機,每個虛擬主機都有一個域名。當engine獲得一個請求時,它把該請求匹配到虛擬主機(host)上,然后把請求交給該主機來處理。
Engine有一個默認主機,當請求無法匹配到任何一個虛擬主機時,將交給默認host來處理。Engine以線程的方式啟動Host。
Host
代表一個虛擬主機,每個虛擬主機和某個網絡域名(Domain Name)相匹配。
每個虛擬主機下都可以部署一個或多個web應用,每個web應用對應于一個context,有一個context path。
當Host獲得一個請求時,將把該請求匹配到某個Context上,然后把該請求交給該Context來處理匹配的方法是“最長匹配”,所以一個path==””的Context將成為該Host的默認Context所有無法和其它Context的路徑名匹配的請求都將最終和該默認Context匹配。
Context
一個Context對應于一個Web應用,一個Web應用由一個或者多個Servlet組成Context在創建的時候將根據配置文件$CATALINA_HOME/conf/web.xml
和$ WEBAPP_HOME/WEB-INF/web.xml
載入Servlet類。當Context獲得請求時,將在自己的映射表(mapping table)中尋找相匹配的Servlet類,如果找到,則執行該類,獲得請求的回應,并返回。
Wrapper
Wrapper 代表一個 Servlet,它負責管理一個 Servlet,包括的 Servlet 的裝載、初始化、執行以及資源回收。Wrapper 是最底層的容器,它沒有子容器了,所以調用它的 addChild 將會報錯。
Wrapper 的實現類是 StandardWrapper,StandardWrapper 還實現了擁有一個 Servlet 初始化信息的 ServletConfig,由此看出 StandardWrapper 將直接和 Servlet 的各種信息打交道。
Connector
Connector將在某個指定的端口上來監聽客戶的請求,把從socket傳遞過來的數據,封裝成Request,傳遞給Engine來處理,并從Engine處獲得響應并返回給客戶。
Tomcat通常會用到兩種Connector:
- Http Connector 在端口8080處偵聽來自客戶browser的http請求。 AJP Connector
- 在端口8009處偵聽來自其它WebServer(Apache)的servlet/jsp代理請求。
Lifecycle
現實生活中大部分的事物都有生命周期,就像人的生老病死一樣。
在編程中也有很多對象是具有生命周期的,從初始化、運行、回收等 會經歷幾個不同的階段。 在tomcat中容器相關的好多組建都實現了Lifecycle接口,當tomcat啟動時,其依賴的下層組件會全部進行初始化。 并且可以對每個組件生命周期中的事件添加監聽器。
例如當服務器啟動的時候,tomcat需要去調用servlet的init方法和初始化容器等一系列操作,而停止的時候,也需要調用servlet的destory方法。而這些都是通過org.apache.catalina.Lifecycle接口來實現的。由這個類來制定各個組件生命周期的規范。
LifecycleListener
在Lifecycle的介紹中提到,Lifecycle會對每個組件生命周期中的事件添加監聽器,也就是addLifecycleListener(LifecycleListener listener)方法,而LifecycleListener就是上面提到的監聽器。
LifecycleEvent
顧名思義,就是當有監聽事件發生的時候,LifecycleEvent會存儲時間類型和數據
/**
* Construct a new LifecycleEvent with the specified parameters.
*
* @param lifecycle Component on which this event occurred
* @param type Event type (required)
* @param data Event data (if any)
*/
public LifecycleEvent(Lifecycle lifecycle, String type, Object data) {
super(lifecycle);
this.type = type;
this.data = data;
}
tomcat 的啟動過程
tomcat的啟動的起點是Server.start()方法,在這里它會依次啟動Container
和 Connector
相關組件,最后到達EndPoint(Tomcat啟動的Socket管理者),完成整個啟動過程。如下圖是個簡易過程:
具體實現過程
StartFirst
/**
* Start the server.
*
* @throws LifecycleException Start error
*/
public void start() throws LifecycleException {
getServer();
getConnector();
server.start();
}
server啟動之前需要準備好Server和Connector,server的默認實現是StandardServer, start()方法在其父類LifecycleBase中
注:LifecycleBase還是
StandardService
,StandardEngine
,StandardHost
,StandardContext
等的父類,所以當調用這些類的start()
方法時其實都是調用此處的start()
方法,而最重要的是在start()
方法中會調用startInternal()
,startInternal()
在LifecycleBase中是抽象方法,具體實現由各個實現類自己定義。
startServer
啟動server其實就是啟動service容器,靠StandardService中的startInternal()實現方法,參考代碼如下:
startService
啟動service其實就是啟動engine容器和connector容器,是在StandardEngine中實現的。參考代碼如下:
啟動Engine
啟動engine其實就是啟動host容器(多線程),是在StandardHost中實現,參考代碼如下:
啟動Host
啟動Host的方式和上圖一樣,都是以線程的方式啟動子Container,這里Host的children為Context
啟動Context(上下文)
啟動Wrapper
loadServlet(加載servlet):
它基本上描述了對 Servlet 的操作,當裝載了 Servlet 后就會調用 Servlet 的init
方法,同時會傳一個 StandardWrapperFacade
對象給 Servlet,這個對象包裝了 StandardWrapper,ServletConfig 與它們的關系圖如下:
啟動Connector
Tomcat的Connector是Coyote connector的一種實現,這是tomcat的官方解釋:The Coyote HTTP/1.1 Connector element represents a Connector component that supports the HTTP/1.1 protocol. It enables Catalina to function as a stand-alone web server, in addition to its ability to execute servlets and JSP pages.
Tomcat8之后默認使用nio作為接受請求策略,默認在Service啟動的時候進行初始化,當然也可以單獨啟動,在默認的構造函數中會初始化ProtocolHandler
tomcat中支持兩種協議的連接器:HTTP/1.1與AJP/1.3
HTTP/1.1協議負責建立HTTP連接,web應用通過瀏覽器訪問tomcat服務器用的就是這個連接器,默認監聽的是8080端口;
AJP/1.3協議負責和其他HTTP服務器建立連接,監聽的是8009端口,比如tomcat和apache或者iis集成時需要用到這個連接器。
Connector
的啟動其實就是ProtocolHandler
的啟動,如下圖:
ProtocolHandler的類結構如下圖:
Connector
的startInternal
方法調用了ProtocolHandle
的start
方法,這個start
方法就在AbstractProtocol
中,如下圖:
EndPoint啟動
EndPoint是tomcat啟動的終點,EndPoint是Tomcat啟動的Socket管理者(注:通過類圖可以看出AbstractEndpoint已經脫離了Lifecycle和LifecycleListener體系,所以它只是一個簡簡單單的Socket管理者),因為是由他直接啟動默認的Nio,在啟動的時候先看看類結構圖:
EndPoint能做什么呢?來看一下他的方法:
createAcceptor
、createExecutor
等方法都是在初始化EndPoint很重要方法,因為在接收請求的時候,通過Acceptor的接收,經過重重模塊,才能一路到達Servlet那么EndPoint的啟動,如下圖:
在這個地方會啟動很多的線程,這些線程大多是用于tomcat接收請求的作用。關于tomcat的接收請求流程,后續會繼續積累。