走進JavaWeb技術世界8:淺析Tomcat9請求處理流程與啓動部署過程

本系列文章將整理到我在GitHub上的《Java面試指南》倉庫,更多精彩內容請到個人倉庫裏查看html

https://github.com/h2pl/Java-Tutorial前端

喜歡的話麻煩點下Star哈python

文章首發於個人我的博客:git

www.how2playlife.com程序員

本文是微信公衆號【Java技術江湖】的《走進JavaWeb技術世界》其中一篇,本文部份內容來源於網絡,爲了把本文主題講得清晰透徹,也整合了不少我認爲不錯的技術博客內容,引用其中了一些比較好的博客文章,若有侵權,請聯繫做者。github

該系列博文會告訴你如何從入門到進階,從servlet到框架,從ssm再到SpringBoot,一步步地學習JavaWeb基礎知識,並上手進行實戰,接着瞭解JavaWeb項目中常常要使用的技術和組件,包括日誌組件、Maven、Junit,等等內容,以便讓你更完整地瞭解整個Java Web技術體系,造成本身的知識框架。面試

爲了更好地總結和檢驗你的學習成果,本系列文章也會提供每一個知識點對應的面試題以及參考答案。數據庫

若是對本系列文章有什麼建議,或者是有什麼疑問的話,也能夠關注公衆號【Java技術江湖】聯繫做者,歡迎你參與本系列博文的創做和修訂。apache

文末贈送8000G的Java架構師學習資料,須要的朋友能夠到文末了解領取方式,資料包括Java基礎、進階、項目和架構師等免費學習資料,更有數據庫、分佈式、微服務等熱門技術學習視頻,內容豐富,兼顧原理和實踐,另外也將贈送做者原創的Java學習指南、Java程序員面試指南等乾貨資源) 編程

不少東西在時序圖中體現的已經很是清楚了,沒有必要再一步一步的做介紹,因此本文以圖爲主,而後對部份內容加以簡單解釋。

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

本文對 Tomcat 的介紹以 Tomcat-9.0.0.M22 爲標準。

Tomcat-9.0.0.M22 是 Tomcat 目前最新的版本,但還沒有發佈,它實現了 Servlet4.0 及 JSP2.3 並提供了不少新特性,須要 1.8 及以上的 JDK 支持等等,詳情請查閱 Tomcat-9.0-doc。

https://tomcat.apache.org/tomcat-9.0-doc/index.html

Overview

Connector 啓動之後會啓動一組線程用於不一樣階段的請求處理過程。

  1. Acceptor 線程組。用於接受新鏈接,並將新鏈接封裝一下,選擇一個 Poller 將新鏈接添加到 Poller 的事件隊列中。
  2. Poller 線程組。用於監聽 Socket 事件,當 Socket 可讀或可寫等等時,將 Socket 封裝一下添加到 worker 線程池的任務隊列中。
  3. worker 線程組。用於對請求進行處理,包括分析請求報文並建立 Request 對象,調用容器的 pipeline 進行處理。

Acceptor、Poller、worker 所在的 ThreadPoolExecutor 都維護在 NioEndpoint 中。

Connector Init and Start

  1. initServerSocket(),經過 ServerSocketChannel.open() 打開一個 ServerSocket,默認綁定到 8080 端口,默認的鏈接等待隊列長度是 100, 當超過 100 個時會拒絕服務。咱們能夠經過配置 conf/server.xml 中 Connector 的 acceptCount 屬性對其進行定製。
  2. createExecutor() 用於建立 Worker 線程池。默認會啓動 10 個 Worker 線程,Tomcat 處理請求過程當中,Woker 最多不超過 200 個。咱們能夠經過配置 conf/server.xml 中 Connector 的 minSpareThreads 和 maxThreads 對這兩個屬性進行定製。
  3. Pollor 用於檢測已就緒的 Socket。默認最多不超過 2 個,Math.min(2,Runtime.getRuntime().availableProcessors());。咱們能夠經過配置 pollerThreadCount 來定製。
  4. Acceptor 用於接受新鏈接。默認是 1 個。咱們能夠經過配置 acceptorThreadCount 對其進行定製。

Request Process

Acceptor

  1. Acceptor 在啓動後會阻塞在 ServerSocketChannel.accept(); 方法處,當有新鏈接到達時,該方法返回一個 SocketChannel。
  2. 配置完 Socket 之後將 Socket 封裝到 NioChannel 中,並註冊到 Poller,值的一提的是,咱們一開始就啓動了多個 Poller 線程,註冊的時候,鏈接是公平的分配到每一個 Poller 的。NioEndpoint 維護了一個 Poller 數組,當一個鏈接分配給 pollers[index] 時,下一個鏈接就會分配給 pollers[(index+1)%pollers.length].
  3. addEvent() 方法會將 Socket 添加到該 Poller 的 PollerEvent 隊列中。到此 Acceptor 的任務就完成了。

Poller

  1. selector.select(1000)。當 Poller 啓動後由於 selector 中並無已註冊的 Channel,因此當執行到該方法時只能阻塞。全部的 Poller 共用一個 Selector,其實現類是 sun.nio.ch.EPollSelectorImpl
  2. events() 方法會將經過 addEvent() 方法添加到事件隊列中的 Socket 註冊到 EPollSelectorImpl,當 Socket 可讀時,Poller 纔對其進行處理
  3. createSocketProcessor() 方法將 Socket 封裝到 SocketProcessor 中,SocketProcessor 實現了 Runnable 接口。worker 線程經過調用其 run() 方法來對 Socket 進行處理。
  4. execute(SocketProcessor) 方法將 SocketProcessor 提交到線程池,放入線程池的 workQueue 中。workQueue 是 BlockingQueue 的實例。到此 Poller 的任務就完成了。

Worker

  • worker 線程被建立之後就執行 ThreadPoolExecutor 的 runWorker() 方法,試圖從 workQueue 中取待處理任務,可是一開始 workQueue 是空的,因此 worker 線程會阻塞在 workQueue.take() 方法。
  • 當新任務添加到 workQueue後,workQueue.take() 方法會返回一個 Runnable,一般是 SocketProcessor,而後 worker 線程調用 SocketProcessor 的 run() 方法對 Socket 進行處理。
  • createProcessor() 會建立一個 Http11Processor, 它用來解析 Socket,將 Socket 中的內容封裝到 Request 中。注意這個 Request 是臨時使用的一個類,它的全類名是 org.apache.coyote.Request,
  • postParseRequest() 方法封裝一下 Request,並處理一下映射關係(從 URL 映射到相應的 Host、Context、Wrapper)。
  1. CoyoteAdapter 將 Rquest 提交給 Container 處理以前,並將 org.apache.coyote.Request 封裝到 org.apache.catalina.connector.Request,傳遞給 Container 處理的 Request 是 org.apache.catalina.connector.Request。
  2. connector.getService().getMapper().map(),用來在 Mapper 中查詢 URL 的映射關係。映射關係會保留到 org.apache.catalina.connector.Request 中,Container 處理階段 request.getHost() 是使用的就是這個階段查詢到的映射主機,以此類推 request.getContext()、request.getWrapper() 都是。
  • connector.getService().getContainer().getPipeline().getFirst().invoke() 會將請求傳遞到 Container 處理,固然了 Container 處理也是在 Worker 線程中執行的,可是這是一個相對獨立的模塊,因此單獨分出來一節。

Container

  • 須要注意的是,基本上每個容器的 StandardPipeline 上都會有多個已註冊的 Valve,咱們只關注每一個容器的 Basic Valve。其餘 Valve 都是在 Basic Valve 前執行。
  • request.getHost().getPipeline().getFirst().invoke() 先獲取對應的 StandardHost,並執行其 pipeline。
  • request.getContext().getPipeline().getFirst().invoke() 先獲取對應的 StandardContext,並執行其 pipeline。
  • request.getWrapper().getPipeline().getFirst().invoke() 先獲取對應的 StandardWrapper,並執行其 pipeline。
  • 最值得說的就是 StandardWrapper 的 Basic Valve,StandardWrapperValve
  1. allocate() 用來加載並初始化 Servlet,值的一提的是 Servlet 並不都是單例的,當 Servlet 實現了 SingleThreadModel 接口後,StandardWrapper 會維護一組 Servlet 實例,這是享元模式。固然了 SingleThreadModel在 Servlet 2.4 之後就棄用了。
  2. createFilterChain() 方法會從 StandardContext 中獲取到全部的過濾器,而後將匹配 Request URL 的全部過濾器挑選出來添加到 filterChain 中。
  3. doFilter() 執行過濾鏈,當全部的過濾器都執行完畢後調用 Servlet 的 service() 方法。

Reference

  1. 《How Tomcat works》
https://www.amazon.com/How-Tomcat-Works-Budi-Kurniawan/dp/097521280X複製代碼
  1. 《Tomcat 架構解析》– 劉光瑞
http://product.dangdang.com/25084132.html複製代碼
  1. Tomcat-9.0-doc
https://tomcat.apache.org/tomcat-9.0-doc/index.html複製代碼
  1. apache-tomcat-9.0.0.M22-src
http://www-eu.apache.org/dist/tomcat/tomcat-9/v9.0.0.M22/src/複製代碼
  1. tomcat架構分析 (connector NIO 實現)
http://gearever.iteye.com/blog/1844203

複製代碼

微信公衆號

我的公衆號:程序員黃小斜

​黃小斜是 985 碩士,阿里巴巴Java工程師,在自學編程、技術求職、Java學習等方面有豐富經驗和獨到看法,但願幫助到更多想要從事互聯網行業的程序員們。​做者專一於 JAVA 後端技術棧,熱衷於分享程序員乾貨、學習經驗、求職心得,以及自學編程和Java技術棧的相關乾貨。​黃小斜是一個斜槓青年,堅持學習和寫做,相信終身學習的力量,但願和更多的程序員交朋友,一塊兒進步和成長!

原創電子書:關注微信公衆號【程序員黃小斜】後回覆【原創電子書】便可領取我原創的電子書《菜鳥程序員修煉手冊:從技術小白到阿里巴巴Java工程師》這份電子書總結了我2年的Java學習之路,包括學習方法、技術總結、求職經驗和麪試技巧等內容,已經幫助不少的程序員拿到了心儀的offer!

程序員3T技術學習資源: 一些程序員學習技術的資源大禮包,關注公衆號後,後臺回覆關鍵字 「資料」 便可免費無套路獲取,包括Java、python、C++、大數據、機器學習、前端、移動端等方向的技術資料。

技術公衆號:Java技術江湖

若是你們想要實時關注我更新的文章以及分享的乾貨的話,能夠關注個人微信公衆號【Java技術江湖】

這是一位阿里 Java 工程師的技術小站。做者黃小斜,專一 Java 相關技術:SSM、SpringBoot、MySQL、分佈式、中間件、集羣、Linux、網絡、多線程,偶爾講點Docker、ELK,同時也分享技術乾貨和學習經驗,致力於Java全棧開發!

Java工程師必備學習資源:關注公衆號後回覆」Java「便可領取 Java基礎、進階、項目和架構師等免費學習資料,更有數據庫、分佈式、微服務等熱門技術學習視頻,內容豐富,兼顧原理和實踐,另外也將贈送做者原創的Java學習指南、Java程序員面試指南等乾貨資源

個人公衆號


微信公衆號

我的公衆號:程序員黃小斜

​黃小斜是 985 碩士,阿里巴巴Java工程師,在自學編程、技術求職、Java學習等方面有豐富經驗和獨到看法,但願幫助到更多想要從事互聯網行業的程序員們。​做者專一於 JAVA 後端技術棧,熱衷於分享程序員乾貨、學習經驗、求職心得,以及自學編程和Java技術棧的相關乾貨。​黃小斜是一個斜槓青年,堅持學習和寫做,相信終身學習的力量,但願和更多的程序員交朋友,一塊兒進步和成長!

原創電子書:關注微信公衆號【程序員黃小斜】後回覆【原創電子書】便可領取我原創的電子書《菜鳥程序員修煉手冊:從技術小白到阿里巴巴Java工程師》這份電子書總結了我2年的Java學習之路,包括學習方法、技術總結、求職經驗和麪試技巧等內容,已經幫助不少的程序員拿到了心儀的offer!

程序員3T技術學習資源: 一些程序員學習技術的資源大禮包,關注公衆號後,後臺回覆關鍵字 「資料」 便可免費無套路獲取,包括Java、python、C++、大數據、機器學習、前端、移動端等方向的技術資料。

技術公衆號:Java技術江湖

若是你們想要實時關注我更新的文章以及分享的乾貨的話,能夠關注個人微信公衆號【Java技術江湖】

這是一位阿里 Java 工程師的技術小站。做者黃小斜,專一 Java 相關技術:SSM、SpringBoot、MySQL、分佈式、中間件、集羣、Linux、網絡、多線程,偶爾講點Docker、ELK,同時也分享技術乾貨和學習經驗,致力於Java全棧開發!

Java工程師必備學習資源:關注公衆號後回覆」Java「便可領取 Java基礎、進階、項目和架構師等免費學習資料,更有數據庫、分佈式、微服務等熱門技術學習視頻,內容豐富,兼顧原理和實踐,另外也將贈送做者原創的Java學習指南、Java程序員面試指南等乾貨資源

個人公衆號

相關文章
相關標籤/搜索