6張圖說清楚Tomcat原理及請求流程-創(chuàng)新互聯(lián)

前言

成都創(chuàng)新互聯(lián)主營尚志網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營網(wǎng)站建設(shè)方案,重慶APP開發(fā)公司,尚志h5微信小程序搭建,尚志網(wǎng)站營銷推廣歡迎尚志等地區(qū)企業(yè)咨詢

很多東西在時序圖中體現(xiàn)的已經(jīng)非常清楚了,沒有必要再一步一步的作介紹,本文以圖為主,然后對部分內(nèi)容加以簡單解釋。

  • 繪制圖形使用的工具是 PlantUML + Visual Studio Code + PlantUML Extension

6張圖說清楚Tomcat原理及請求流程

本文對 Tomcat 的介紹以 Tomcat-9.0.0.M22 為標(biāo)準(zhǔn)。

Tomcat-9.0.0.M22 是 Tomcat 目前最新的版本,但尚未發(fā)布,它實現(xiàn)了 Servlet4.0 及 JSP2.3 并提供了很多新特性,需要 1.8 及以上的 JDK 支持等等,詳情請查閱 Tomcat-9.0-doc

  • Overview

  • Connector Init and Start

  • Requtst Process

  • Acceptor

  • Poller

  • Worker

  • Container

  • At last

Overview

6張圖說清楚Tomcat原理及請求流程

  1. Connector 啟動以后會啟動一組線程用于不同階段的請求處理過程。

  2. Acceptor 線程組。用于接受新連接,并將新連接封裝一下,選擇一個 Poller 將新連接添加到 Poller 的事件隊列中。

  3. Poller 線程組。用于監(jiān)聽 Socket 事件,當(dāng) Socket 可讀或可寫等等時,將 Socket 封裝一下添加到 worker 線程池的任務(wù)隊列中。

  4. worker 線程組。用于對請求進(jìn)行處理,包括分析請求報文并創(chuàng)建 Request 對象,調(diào)用容器的 pipeline 進(jìn)行處理。

  • Acceptor、 Poller、 worker 所在的 ThreadPoolExecutor 都維護(hù)在 NioEndpoint 中。

Connector Init and Start

6張圖說清楚Tomcat原理及請求流程

  1. initServerSocket(),通過 ServerSocketChannel.open() 打開一個 ServerSocket,默認(rèn)綁定到 8080 端口,默認(rèn)的連接等待隊列長度是 100, 當(dāng)超過 100 個時會拒絕服務(wù)。我們可以通過配置 conf/server.xml 中 Connector 的 acceptCount 屬性對其進(jìn)行定制。

  2. createExecutor() 用于創(chuàng)建 Worker 線程池。默認(rèn)會啟動 10 個 Worker 線程,Tomcat 處理請求過程中,Woker 最多不超過 200 個。我們可以通過配置 conf/server.xml 中 Connector 的 minSpareThreads 和 maxThreads 對這兩個屬性進(jìn)行定制。

  3. Pollor 用于檢測已就緒的 Socket。 默認(rèn)最多不超過 2 個, Math.min(2,Runtime.getRuntime().availableProcessors());。我們可以通過配置 pollerThreadCount 來定制。

  4. Acceptor 用于接受新連接。默認(rèn)是 1 個。我們可以通過配置 acceptorThreadCount 對其進(jìn)行定制。

    歡迎大家關(guān)注我的公種浩【程序員追風(fēng)】,文章都會在里面更新,整理的資料也會放在里面。

Requtst Process

Acceptor

6張圖說清楚Tomcat原理及請求流程

  1. Acceptor 在啟動后會阻塞在 ServerSocketChannel.accept(); 方法處,當(dāng)有新連接到達(dá)時,該方法返回一個 SocketChannel。

  2. 配置完 Socket 以后將 Socket 封裝到 NioChannel 中,并注冊到 Poller, 值的一提的是,我們一開始就啟動了多個 Poller 線程,注冊的時候,連接是公平的分配到每個 Poller 的。 NioEndpoint 維護(hù)了一個 Poller 數(shù)組,當(dāng)一個連接分配給 pollers[index] 時,下一個連接就會分配給 pollers[(index+1)%pollers.length].

  3. addEvent() 方法會將 Socket 添加到該 Poller 的 PollerEvent 隊列中。到此 Acceptor 的任務(wù)就完成了。

Poller

6張圖說清楚Tomcat原理及請求流程

  1. selector.select(1000)。當(dāng) Poller 啟動后因為 selector 中并沒有已注冊的 Channel,所以當(dāng)執(zhí)行到該方法時只能阻塞。所有的 Poller 共用一個 Selector,其實現(xiàn)類是 sun.nio.ch.EPollSelectorImpl

  2. events() 方法會將通過 addEvent() 方法添加到事件隊列中的 Socket 注冊到 EPollSelectorImpl,當(dāng) Socket 可讀時, Poller 才對其進(jìn)行處理

  3. createSocketProcessor() 方法將 Socket 封裝到 SocketProcessor 中, SocketProcessor 實現(xiàn)了 Runnable 接口。 worker 線程通過調(diào)用其 run() 方法來對 Socket 進(jìn)行處理。

  4. execute(SocketProcessor) 方法將 SocketProcessor 提交到線程池,放入線程池的 workQueue 中。 workQueue 是 BlockingQueue 的實例。到此 Poller 的任務(wù)就完成了。

Worker

6張圖說清楚Tomcat原理及請求流程

  1. worker 線程被創(chuàng)建以后就執(zhí)行 ThreadPoolExecutor 的 runWorker() 方法,試圖從 workQueue 中取待處理任務(wù),但是一開始 workQueue 是空的,所以 worker 線程會阻塞在 workQueue.take() 方法。

  2. 當(dāng)新任務(wù)添加到 workQueue后, workQueue.take() 方法會返回一個 Runnable,通常是 SocketProcessor, 然后 worker 線程調(diào)用 SocketProcessor 的 run() 方法對 Socket 進(jìn)行處理。

  3. createProcessor() 會創(chuàng)建一個 Http11Processor, 它用來解析 Socket,將 Socket 中的內(nèi)容封裝到 Request 中。注意這個 Request 是臨時使用的一個類,它的全類名是 org.apache.coyote.Request,

  4. postParseRequest() 方法封裝一下 Request,并處理一下映射關(guān)系 (從 URL 映射到相應(yīng)的 Host、 Context、 Wrapper)。

  5. CoyoteAdapter 將 Rquest 提交給 Container 處理之前,并將 org.apache.coyote.Request 封裝到 org.apache.catalina.connector.Request,傳遞給 Container 處理的 Request 是 org.apache.catalina.connector.Request。

  6. connector.getService().getMapper().map(),用來在 Mapper 中查詢 URL 的映射關(guān)系。映射關(guān)系會保留到 org.apache.catalina.connector.Request 中, Container 處理階段 request.getHost() 是使用的就是這個階段查詢到的映射主機(jī),以此類推 request.getContext()、 request.getWrapper() 都是。

  7. connector.getService().getContainer().getPipeline().getFirst().invoke() 會將請求傳遞到 Container 處理,當(dāng)然了 Container 處理也是在 Worker 線程中執(zhí)行的,但是這是一個相對獨立的模塊,所以單獨分出來一節(jié)。

Container

6張圖說清楚Tomcat原理及請求流程

  1. 需要注意的是,基本上每一個容器的 StandardPipeline 上都會有多個已注冊的 Valve,我們只關(guān)注每個容器的 Basic Valve。其他 Valve 都是在 Basic Valve 前執(zhí)行。

  2. request.getHost().getPipeline().getFirst().invoke() 先獲取對應(yīng)的 StandardHost,并執(zhí)行其 pipeline。

  3. request.getContext().getPipeline().getFirst().invoke() 先獲取對應(yīng)的 StandardContext, 并執(zhí)行其 pipeline。

  4. request.getWrapper().getPipeline().getFirst().invoke() 先獲取對應(yīng)的 StandardWrapper,并執(zhí)行其 pipeline。

  5. 最值得說的就是 StandardWrapper 的 Basic Valve, StandardWrapperValve

  6. allocate() 用來加載并初始化 Servlet,值的一提的是 Servlet 并不都是單例的,當(dāng) Servlet 實現(xiàn)了 SingleThreadModel 接口后, StandardWrapper 會維護(hù)一組 Servlet 實例,這是享元模式。當(dāng)然了 SingleThreadModel 在 Servlet 2.4 以后就棄用了。

  7. createFilterChain() 方法會從 StandardContext 中獲取到所有的過濾器,然后將匹配 Request URL 的所有過濾器挑選出來添加到 filterChain 中。

  8. doFilter() 執(zhí)行過濾鏈, 當(dāng)所有的過濾器都執(zhí)行完畢后調(diào)用 Servlet 的 service() 方法。

Reference

  1. 《How Tomcat works》

  2. 《Tomcat 架構(gòu)解析》-- 劉光瑞

  3. Tomcat-9.0-doc

  4. apache-tomcat-9.0.0.M22-src

  5. tomcat 架構(gòu)分析 (connector NIO 實現(xiàn))

最后

歡迎大家一起交流,喜歡文章記得點個贊喲,感謝支持!

創(chuàng)新互聯(lián)www.cdcxhl.cn,專業(yè)提供香港、美國云服務(wù)器,動態(tài)BGP最優(yōu)骨干路由自動選擇,持續(xù)穩(wěn)定高效的網(wǎng)絡(luò)助力業(yè)務(wù)部署。公司持有工信部辦法的idc、isp許可證, 機(jī)房獨有T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確進(jìn)行流量調(diào)度,確保服務(wù)器高可用性。佳節(jié)活動現(xiàn)已開啟,新人活動云服務(wù)器買多久送多久。

當(dāng)前標(biāo)題:6張圖說清楚Tomcat原理及請求流程-創(chuàng)新互聯(lián)
文章轉(zhuǎn)載:http://muchs.cn/article46/cdogeg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信小程序手機(jī)網(wǎng)站建設(shè)、定制網(wǎng)站、企業(yè)網(wǎng)站制作品牌網(wǎng)站設(shè)計、App設(shè)計

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站優(yōu)化排名