更新時間:2022-11-18 來源:黑馬程序員 瀏覽量:
> 容器,簡單理解就是用來裝東西的工具。在Tomcat里面,容器被設(shè)計用來裝載Servlet, 也就是我們平常寫的普通的Servlet ,就會存放在容器里面。這也就是咱們平常念叨的Servlet容器,其實從廣義上理解,Servlet容器是指Tomcat,從狹義上理解,Servlet容器,只是Tomcat里面的一個組件而已。
1.容器概述
Tomcat采用分層結(jié)構(gòu)設(shè)計了4種容器,這4種容器分別是: Engine 、Host 、Context 、Wrap 。它們鈞繼承 Container 容器接口。這樣設(shè)計使得Tomcat在處理請求時,分工更加明確,也使得容器具有很好的靈活性。
其中從左到右: Engine 表示引擎,用來管理多個虛擬站點,一個Service最多只能有一個Engine。 Host代表虛擬主機,或者表示站點。其實就是我們配置出來的虛擬映射地址。Context表示一個Web應(yīng)用,Wrap 名為包裝,它其實就是內(nèi)部包裝著我們寫的Servlet。
為了方便大家理解,我們可以從Tomcat里面的server.xml中看出來一些端倪。
這四個容器呈現(xiàn)的是一個父子包含關(guān)系:
2. 定位Servlet
> 在Tomcat里面使用Mapper 映射器來實現(xiàn)Servlet的定位工作。在最初啟動項目的時候,Tomcat就開始解析了項目的配置信息,然后使用Mapper來保存了具體的映射地址和Host、Context、Wrap的對應(yīng)關(guān)系。當(dāng)請求到來的時候,就會到Mapper里面去查找匹配的Wrap(Servlet),然后調(diào)用。當(dāng)我們?yōu)榱朔奖憷斫?,我們可以淺顯的認為Mapper其實就是一個類似Map鍵值對的容器。
2.1 全局概覽
比如: 下面的圖示,我們可以把瑞吉點餐項目的面向管理員后臺項目和面向用戶前端項目部署在同一個Tomcat上,為了隔離它們,我們通過配置虛擬域名,也就是兩個Host。而用戶系統(tǒng),訂單系統(tǒng),產(chǎn)品系統(tǒng),購物車系統(tǒng)又都是可以獨立運行的應(yīng)用,所以我們可以配備4個Context來對應(yīng)它們。最后一排的Wrap,其實就是各自系統(tǒng)中的Servlet了。
2.2 請求到來
> 此時用戶使用 http://user.reggie.com:8080/cart/delete 來訪問。
2.2.1 定位Service和Engine
由于來訪的時候,使用的是8080端口,正好被Http連接器捕捉到。在Tomcat里面,Service里面包含著: 連接器和容器。找到了連接器,也就意味著找到了容器,這也就意味著Engine就確定了。
2.2.2 定位Host
Service和Engine確定了之后,就在Mapper中,通過路徑地址,找到響應(yīng)的Host容器。由于使用的是user.reggie.com 訪問,所以這就確定了是Host2這個容器。
2.2.3 定位Context
Host確定了之后,繼續(xù)在Mapper中查找。由于使用的/cart訪問,所以這就定位到了Context4這個應(yīng)用。
2.2.4 定位Wrap
Context確定了之后,后續(xù)也就能根據(jù)地址 /delete,輕而易舉的找到 Wrap6 這個容器。最后也就定位到了Servlet。
2.3 請求傳遞
> Tomcat 里面是如何把請求從最外層的容器Engine,一直往里傳遞到Wrap,然后執(zhí)行Servlet的調(diào)用的呢?
>
> 答案是使用 Pipeline-Valve 管道。
>
> Pipeline-Valve 是責(zé)任鏈模式,責(zé)任鏈模式是指在一個請求處理的過程中有很多處理者依次對請求進行處理,每個處理者負責(zé)做自己相應(yīng)的處理,處理完之后將再調(diào)用下一個處理者繼續(xù)處理。
下面通過一個張簡單的草圖來描述:
每一個容器都有一個Pipeline對象,中間的每一個圓圈,其實表示的是一個Valve,它表示處理點。在Pipeline里面維護這Valve的鏈表。只要執(zhí)行了第一個Pipeline的Valve,這個容器中的Pipeline就會被調(diào)用,直到最后末端的Basic的Valve,它負責(zé)去連接下一個子容器的第一個Valve處理點。這樣不斷的串聯(lián)起來,最終就到達了Servlet。
值得注意的是: 在Wrap的最后一個Basic的Valve的處理點里面,它會創(chuàng)建一個Filter過濾器鏈,然后在doFilter方法中最終調(diào)用Servlet的service方法。
3. 總結(jié)
本文主要給大家描述了Tomcat了里面的容器結(jié)構(gòu),以及請求到來的時候,是如何識別到底執(zhí)行了哪個Servlet。請求的鏈式調(diào)用是基于 Pipeline-Valve 責(zé)任鏈來完成的,這樣的設(shè)計使得系統(tǒng)具有良好的可擴展性,如果需要擴展容器本身的功能,只需要增加相應(yīng)的 Valve 即可。