Tomcat 組成與工作原理
點(diǎn)擊上方“程序員大白”,選擇“星標(biāo)”公眾號(hào)
重磅干貨,第一時(shí)間送達(dá)

來(lái)自:掘金,作者:VectorJin
鏈接:https://juejin.cn/post/6844903473482317837
Tomcat 是什么

Servlet 容器
Tomcat 組成如下圖:主要有 Container 和 Connector 以及相關(guān)組件構(gòu)成。
Server:指的就是整個(gè) Tomcat 服 務(wù)器,包含多組服務(wù),負(fù)責(zé)管理和 啟動(dòng)各個(gè) Service,同時(shí)監(jiān)聽(tīng) 8005 端口發(fā)過(guò)來(lái)的 shutdown 命令,用于關(guān)閉整個(gè)容器;
Service:Tomcat 封裝的、對(duì)外提供完整的、基于組件的 Web 服務(wù), 包含 Connectors、Container 兩個(gè)核心組件,以及多個(gè)功能組件,各個(gè) Service 之間是獨(dú)立的,但是共享 同一 JVM 的資源;
Connector:Tomcat 與外部世界的連接器,監(jiān)聽(tīng)固定端口接收外部請(qǐng)求,傳遞給 Container,并將 Container 處理的結(jié)果返回給外部;
Container:Catalina,Servlet 容器,內(nèi)部有多層容器組成,用于管理 Servlet 生命周期,調(diào)用 servlet 相關(guān)方法;
Loader:封裝了 Java ClassLoader,用于 Container 加載類文件;
Realm:Tomcat 中為 Web 應(yīng)用程序提供訪問(wèn)認(rèn)證和角色管理的機(jī)制;
JMX:Java SE 中定義技術(shù)規(guī)范,是一個(gè)為應(yīng)用程序、設(shè)備、系統(tǒng)等植入管理功能的框架,通過(guò) JMX 可以遠(yuǎn)程監(jiān)控 Tomcat 的運(yùn)行狀態(tài);
Jasper:Tomcat 的 JSP 解析引擎,用于將 JSP 轉(zhuǎn)換成 Java 文件,并編譯成 class 文件。
Session:負(fù)責(zé)管理和創(chuàng)建 Session,以及 Session 的持久化(可自定義),支持 Session 的集 群。
Pipeline:在容器中充當(dāng)管道的作用,管道中可以設(shè)置各種 valve(閥門(mén)),請(qǐng)求和響應(yīng)在經(jīng)由管道中各個(gè)閥門(mén)處理,提供了一種靈活可配置的處理請(qǐng)求和響應(yīng)的機(jī)制。
Naming:命名服務(wù),JNDI, Java 命名和目錄接口,是一組在 Java 應(yīng)用中訪問(wèn)命名和目錄服務(wù)的 API。命名服務(wù)將名稱和對(duì)象聯(lián)系起來(lái),使得我們可以用名稱訪問(wèn)對(duì)象,目錄服務(wù)也是一種命名 服務(wù),對(duì)象不但有名稱,還有屬性。Tomcat 中可以使用 JNDI 定義數(shù)據(jù)源、配置信息,用于開(kāi)發(fā)與部署的分離。

Engine:Servlet 的頂層容器,包含一 個(gè)或多個(gè) Host 子容器;
Host:虛擬主機(jī),負(fù)責(zé) Web 應(yīng)用的部 署和 Context 的創(chuàng)建;
Context:Web 應(yīng)用上下文,包含多個(gè) Wrapper,負(fù)責(zé) Web 配置的解析、管 理所有的 Web 資源;
Wrapper:最底層的容器,是對(duì) Servlet 的封裝,負(fù)責(zé) Servlet 實(shí)例的創(chuàng) 建、執(zhí)行和銷毀。

EngineConfig:主要打印啟動(dòng)和停止日志
HostConfig:主要處理部署應(yīng)用,解析應(yīng)用 META-INF/context.xml 并創(chuàng)建應(yīng)用的 Context
ContextConfig:主要解析并合并 web.xml,掃描應(yīng)用的各類 Eeb 資源(filter、servlet、listener)


List
>?results?=?new?ArrayList >();
for?(int?i?=?0;?i?????results.add(startStopExecutor.submit(new?StartChild(children[i])));
}
boolean?fail?=?false;
for?(Futureresult :results)?{
????try?{
????????result.get();
????}?catch?(Exception?e)?{
????????log.error(sm.getString("containerBase.threadedStartFailed"),?e);
????????fail?=?true;
????}
}
catalina.home:安裝目錄
catalina.base:工作目錄
默認(rèn)值:user.dir
Server.xml 配置 Host 元素,指定 appBase 屬性,默認(rèn) $catalina.base/webapps/
Server.xml 配置 Context 元素,指定 docBase,元素,指定 Web 應(yīng)用的路徑
自定義配置在 $catalina.base/EngineName/HostName/XXX.xml 配置 Context 元素
掃描 appbase 路徑下的所有文件夾和 war 包,解析各個(gè)應(yīng)用的 META-INF/context.xml,并創(chuàng)建 StandardContext,并將 Context 加入到 Host 的子容器中。
解析 $catalina.base/EngineName/HostName/ 下的所有 Context 配置,找到相應(yīng) Web 應(yīng)用的位置,解析各個(gè)應(yīng)用的 META-INF/context.xml,并創(chuàng)建 StandardContext,并將 Context 加入到 Host 的子容器中。
HostConfig 并沒(méi)有實(shí)際解析 Context.xml,而是在 ContextConfig 中進(jìn)行的。
HostConfig 中會(huì)定期檢查 watched 資源文件(context.xml 配置文件)
先解析全局的配置 config/context.xml
然后解析 Host 的默認(rèn)配置 EngineName/HostName/context.xml.default
最后解析應(yīng)用的 META-INF/context.xml
先解析全局的配置 config/web.xml
然后解析 Host 的默認(rèn)配置 EngineName/HostName/web.xml.default 接著解析應(yīng)用的 MEB-INF/web.xml
掃描應(yīng)用 WEB-INF/lib/ 下的 jar 文件,解析其中的 META-INF/web-fragment.xml 最后合并 xml 封裝成 WebXml,并設(shè)置 Context
掃描 Web 應(yīng)用和 jar 中的注解(Filter、Listener、Servlet)就是上述步驟中進(jìn)行的。
容器的定期執(zhí)行:backgroundProcess,由 ContainerBase 來(lái)實(shí)現(xiàn)的,并且只有在頂層容器中才會(huì)開(kāi)啟線程。(backgroundProcessorDelay=10 標(biāo)志位來(lái)控制)

請(qǐng)求到達(dá) server 端,server 根據(jù) url 映射到相應(yīng)的 Servlet
判斷 Servlet 實(shí)例是否存在,不存在則加載和實(shí)例化 Servlet 并調(diào)用 init 方法
Server 分別創(chuàng)建 Request 和 Response 對(duì)象,調(diào)用 Servlet 實(shí)例的 service 方法(service 方法內(nèi)部會(huì)根據(jù) http 請(qǐng)求方法類型調(diào)用相應(yīng)的 doXXX 方法)
doXXX 方法內(nèi)為業(yè)務(wù)邏輯實(shí)現(xiàn),從 Request 對(duì)象獲取請(qǐng)求參數(shù),處理完畢之后將結(jié)果通過(guò) response 對(duì)象返回給調(diào)用方
當(dāng) Server 不再需要 Servlet 時(shí)(一般當(dāng) Server 關(guān)閉時(shí)),Server 調(diào)用 Servlet 的 destroy() 方法。

根據(jù) server.xml 配置的指定的 connector 以及端口監(jiān)聽(tīng) http、或者 ajp 請(qǐng)求
請(qǐng)求到來(lái)時(shí)建立連接,解析請(qǐng)求參數(shù),創(chuàng)建 Request 和 Response 對(duì)象,調(diào)用頂層容器 Pipeline 的 invoke 方法
容器之間層層調(diào)用,最終調(diào)用業(yè)務(wù) servlet 的 service 方法
Connector 將 response 流中的數(shù)據(jù)寫(xiě)到 socket 中

JSP引擎

編譯階段:servlet 容器編譯 servlet 源文件,生成 servlet 類
初始化階段:加載與 JSP 對(duì)應(yīng)的 servlet 類,創(chuàng)建其實(shí)例,并調(diào)用它的初始化方法
執(zhí)行階段:調(diào)用與 JSP 對(duì)應(yīng)的 servlet 實(shí)例的服務(wù)方法
銷毀階段:調(diào)用與 JSP 對(duì)應(yīng)的 servlet 實(shí)例的銷毀方法,然后銷毀 servlet 實(shí)例
代碼片段:<% 代碼片段 %>
JSP聲明:<%! declaration; [ declaration; ]+ ... %>
JSP表達(dá)式:<%= 表達(dá)式 %>
JSP注釋:<%-- 注釋 --%>
JSP指令:<%@ directive attribute=“value” %>
JSP行為:
HTML元素:html/head/body/div/p/……
JSP隱式對(duì)象:request、response、out、session、application、config、 pageContext、page、Exception
代碼片段:包含任意量的 Java 語(yǔ)句、變量、方法或表達(dá)式
JSP 聲明:一個(gè)聲明語(yǔ)句可以聲明一個(gè)或多個(gè)變量、方法,供后面的 Java 代碼使用
JSP 表達(dá)式:輸出 Java 表達(dá)式的值,String 形式;
JSP 注釋:為代碼作注釋以及將某段代碼注釋掉
JSP 指令:用來(lái)設(shè)置與整個(gè) JSP 頁(yè)面相關(guān)的屬性:
<%@ page ... %> 定義頁(yè)面的依賴屬性,比如 language、contentType、errorPage、 isErrorPage、import、isThreadSafe、session 等等
<%@ include ... %> 包含其他的 JSP 文件、HTML 文件或文本文件,是該 JSP 文件的一部分,會(huì)被同時(shí)編譯執(zhí)行
<%@ taglib ... %> 引入標(biāo)簽庫(kù)的定義,可以是自定義標(biāo)簽
JSP 行為:jsp:include、jsp:useBean、jsp:setProperty、jsp:getProperty、jsp:forward

代碼片段:在 _jspService() 方法內(nèi)直接輸出
JSP 聲明:在 servlet 類中進(jìn)行輸出
JSP 表達(dá)式:在 _jspService() 方法內(nèi)直接輸出
JSP 注釋:直接忽略,不輸出
JSP 指令:根據(jù)不同指令進(jìn)行區(qū)分,include:對(duì)引入的文件進(jìn)行解析;page 相關(guān)的屬性會(huì)做為 JSP 的屬性,影響的是解析和請(qǐng)求處理時(shí)的行為
JSP 行為:不同的行為有不同的處理方式,jsp:useBean 為例,會(huì)從 pageContext 根據(jù) scope 的 類別獲取 bean 對(duì)象,如果沒(méi)有會(huì)創(chuàng)建 bean,同時(shí)存到相應(yīng) scope 的 pageContext 中
HTML:在 _jspService() 方法內(nèi)直接輸出
JSP 隱式對(duì)象:在 _jspService() 方法會(huì)進(jìn)行聲明,只能在方法中使用
Connector

HTTP,HTTP 是超文本傳輸協(xié)議,是客戶端瀏覽器或其他程序與 Web 服務(wù)器之間的應(yīng)用層通信協(xié)議
AJP,Apache JServ 協(xié)議(AJP)是一種二進(jìn)制協(xié)議,專門(mén)代理從 Web 服務(wù)器到位于后端的應(yīng)用程序服務(wù)器的入站請(qǐng)求




JIO:用 java.io 編寫(xiě)的 TCP 模塊,阻塞IO
NIO:用 java.nio 編寫(xiě)的 TCP 模塊,非阻塞 IO,(IO 多路復(fù)用)
APR:全稱 Apache Portable Runtime,使用 JNI 的方式來(lái)進(jìn)行讀取文件以及進(jìn)行網(wǎng)絡(luò)傳輸
Support Polling:是否支持基于 IO 多路復(fù)用的 socket 事件輪詢
Polling Size:輪詢的最大連接數(shù)
Wait for next Request:在等待下一個(gè)請(qǐng)求時(shí),處理線程是否釋放,BIO 是沒(méi)有釋放的,所以在 keep-alive=true 的情況下處理的并發(fā)連接數(shù)有限
Read Request Headers:由于 request header 數(shù)據(jù)較少,可以由容器提前解析完畢,不需要阻塞
Read Request Body:讀取 request body 的數(shù)據(jù)是應(yīng)用業(yè)務(wù)邏輯的事情,同時(shí) Servlet 的限制,是需要阻塞讀取的
Write Response:跟讀取 request body 的邏輯類似,同樣需要阻塞寫(xiě)



Begin:新的請(qǐng)求連接接入調(diào)用,可進(jìn)行與 Request 和 Response 相關(guān)的對(duì)象初始化操作,并保存 response 對(duì)象,用于后續(xù)寫(xiě)入數(shù)據(jù)
Read:請(qǐng)求連接有數(shù)據(jù)可讀時(shí)調(diào)用
End:當(dāng)數(shù)據(jù)可用時(shí),如果讀取到文件結(jié)束或者 response 被關(guān)閉時(shí)則被調(diào)用
Error:在連接上發(fā)生異常時(shí)調(diào)用,數(shù)據(jù)讀取異常、連接斷開(kāi)、處理異常、socket 超時(shí)
Read:在 post 請(qǐng)求有數(shù)據(jù),但在begin事件中沒(méi)有處理,則會(huì)調(diào)用read,如果read沒(méi)有讀取數(shù)據(jù),在會(huì)觸發(fā)Error回調(diào),關(guān)閉socket
End:當(dāng)socket超時(shí),并且response被關(guān)閉時(shí)也會(huì)調(diào)用;server被關(guān)閉時(shí)調(diào)用
Error:除了socket超時(shí)不會(huì)關(guān)閉socket,其他都會(huì)關(guān)閉socket
End和Error時(shí)間觸發(fā)時(shí)應(yīng)關(guān)閉當(dāng)前comet會(huì)話,即調(diào)用CometEvent的close方法 Note:在事件觸發(fā)時(shí)要做好線程安全的操作

首先,Servlet 接收到請(qǐng)求之后,request 數(shù)據(jù)解析;
接著,調(diào)用業(yè)務(wù)接口的某些方法,以完成業(yè)務(wù)處理;
最后,根據(jù)處理的結(jié)果提交響應(yīng),Servlet 線程結(jié)束。

客戶端發(fā)送一個(gè)請(qǐng)求
Servlet 容器分配一個(gè)線程來(lái)處理容器中的一個(gè) Servlet
Servlet 調(diào)用 request.startAsync(),保存 AsyncContext,然后返回
任何方式存在的容器線程都將退出,但是 response 仍然保持開(kāi)放
業(yè)務(wù)線程使用保存的 AsyncContext 來(lái)完成響應(yīng)(線程池)
客戶端收到響應(yīng)
onStartAsync:Request 調(diào)用 startAsync 方法時(shí)觸發(fā)
onComplete:syncContext 調(diào)用 complete 方法時(shí)觸發(fā)
onError:處理請(qǐng)求的過(guò)程出現(xiàn)異常時(shí)觸發(fā)
onTimeout:socket 超時(shí)觸發(fā)
推薦閱讀
關(guān)于程序員大白
程序員大白是一群哈工大,東北大學(xué),西湖大學(xué)和上海交通大學(xué)的碩士博士運(yùn)營(yíng)維護(hù)的號(hào),大家樂(lè)于分享高質(zhì)量文章,喜歡總結(jié)知識(shí),歡迎關(guān)注[程序員大白],大家一起學(xué)習(xí)進(jìn)步!

