本系列文章將整理到我在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 啓動之後會啓動一組線程用於不一樣階段的請求處理過程。
- Acceptor 線程組。用於接受新鏈接,並將新鏈接封裝一下,選擇一個 Poller 將新鏈接添加到 Poller 的事件隊列中。
- Poller 線程組。用於監聽 Socket 事件,當 Socket 可讀或可寫等等時,將 Socket 封裝一下添加到 worker 線程池的任務隊列中。
- worker 線程組。用於對請求進行處理,包括分析請求報文並建立 Request 對象,調用容器的 pipeline 進行處理。
Acceptor、Poller、worker 所在的 ThreadPoolExecutor 都維護在 NioEndpoint 中。
Connector Init and Start
- initServerSocket(),經過 ServerSocketChannel.open() 打開一個 ServerSocket,默認綁定到 8080 端口,默認的鏈接等待隊列長度是 100, 當超過 100 個時會拒絕服務。咱們能夠經過配置 conf/server.xml 中 Connector 的 acceptCount 屬性對其進行定製。
- createExecutor() 用於建立 Worker 線程池。默認會啓動 10 個 Worker 線程,Tomcat 處理請求過程當中,Woker 最多不超過 200 個。咱們能夠經過配置 conf/server.xml 中 Connector 的 minSpareThreads 和 maxThreads 對這兩個屬性進行定製。
- Pollor 用於檢測已就緒的 Socket。默認最多不超過 2 個,Math.min(2,Runtime.getRuntime().availableProcessors());。咱們能夠經過配置 pollerThreadCount 來定製。
- Acceptor 用於接受新鏈接。默認是 1 個。咱們能夠經過配置 acceptorThreadCount 對其進行定製。
Request Process
Acceptor
- Acceptor 在啓動後會阻塞在 ServerSocketChannel.accept(); 方法處,當有新鏈接到達時,該方法返回一個 SocketChannel。
- 配置完 Socket 之後將 Socket 封裝到 NioChannel 中,並註冊到 Poller,值的一提的是,咱們一開始就啓動了多個 Poller 線程,註冊的時候,鏈接是公平的分配到每一個 Poller 的。NioEndpoint 維護了一個 Poller 數組,當一個鏈接分配給 pollers[index] 時,下一個鏈接就會分配給 pollers[(index+1)%pollers.length].
- addEvent() 方法會將 Socket 添加到該 Poller 的 PollerEvent 隊列中。到此 Acceptor 的任務就完成了。
Poller
- selector.select(1000)。當 Poller 啓動後由於 selector 中並無已註冊的 Channel,因此當執行到該方法時只能阻塞。全部的 Poller 共用一個 Selector,其實現類是 sun.nio.ch.EPollSelectorImpl
- events() 方法會將經過 addEvent() 方法添加到事件隊列中的 Socket 註冊到 EPollSelectorImpl,當 Socket 可讀時,Poller 纔對其進行處理
- createSocketProcessor() 方法將 Socket 封裝到 SocketProcessor 中,SocketProcessor 實現了 Runnable 接口。worker 線程經過調用其 run() 方法來對 Socket 進行處理。
- 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)。
- CoyoteAdapter 將 Rquest 提交給 Container 處理以前,並將 org.apache.coyote.Request 封裝到 org.apache.catalina.connector.Request,傳遞給 Container 處理的 Request 是 org.apache.catalina.connector.Request。
- 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
- allocate() 用來加載並初始化 Servlet,值的一提的是 Servlet 並不都是單例的,當 Servlet 實現了 SingleThreadModel 接口後,StandardWrapper 會維護一組 Servlet 實例,這是享元模式。固然了 SingleThreadModel在 Servlet 2.4 之後就棄用了。
- createFilterChain() 方法會從 StandardContext 中獲取到全部的過濾器,而後將匹配 Request URL 的全部過濾器挑選出來添加到 filterChain 中。
- doFilter() 執行過濾鏈,當全部的過濾器都執行完畢後調用 Servlet 的 service() 方法。
Reference
- 《How Tomcat works》
https://www.amazon.com/How-Tomcat-Works-Budi-Kurniawan/dp/097521280X複製代碼
- 《Tomcat 架構解析》– 劉光瑞
http://product.dangdang.com/25084132.html複製代碼
- Tomcat-9.0-doc
https://tomcat.apache.org/tomcat-9.0-doc/index.html複製代碼
- apache-tomcat-9.0.0.M22-src
http://www-eu.apache.org/dist/tomcat/tomcat-9/v9.0.0.M22/src/複製代碼
- 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程序員面試指南等乾貨資源