<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          面試官:談?wù)?Tomcat 請(qǐng)求處理流程,我一臉懵逼。。

          共 4609字,需瀏覽 10分鐘

           ·

          2021-06-27 14:08


          上一篇:深夜看了張一鳴的微博,讓我越想越后怕


          來源:github.com/c-rainstorm/blog/blob/master/tomcat/

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

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

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

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

          Overview

          Connector 啟動(dòng)以后會(huì)啟動(dòng)一組線程用于不同階段的請(qǐng)求處理過程。

          1. Acceptor 線程組。用于接受新連接,并將新連接封裝一下,選擇一個(gè) Poller 將新連接添加到 Poller 的事件隊(duì)列中。
          2. Poller 線程組。用于監(jiān)聽 Socket 事件,當(dāng) Socket 可讀或可寫等等時(shí),將 Socket 封裝一下添加到 worker 線程池的任務(wù)隊(duì)列中。
          3. worker 線程組。用于對(duì)請(qǐng)求進(jìn)行處理,包括分析請(qǐng)求報(bào)文并創(chuàng)建 Request 對(duì)象,調(diào)用容器的 pipeline 進(jìn)行處理。

          Acceptor、Poller、worker 所在的 ThreadPoolExecutor 都維護(hù)在 NioEndpoint 中。另外,Tomcat 系列面試題和答案全部整理好了,微信搜索互聯(lián)網(wǎng)架構(gòu)師,在后臺(tái)發(fā)送:2T,可以在線閱讀。

          Connector Init and Start

          initServerSocket(),通過 ServerSocketChannel.open() 打開一個(gè) ServerSocket,默認(rèn)綁定到 8080 端口,默認(rèn)的連接等待隊(duì)列長度是 100, 當(dāng)超過 100 個(gè)時(shí)會(huì)拒絕服務(wù)。
          我們可以通過配置 conf/server.xml 中 Connector 的 acceptCount 屬性對(duì)其進(jìn)行定制。
          1. createExecutor() 用于創(chuàng)建 Worker 線程池。默認(rèn)會(huì)啟動(dòng) 10 個(gè) Worker 線程,Tomcat 處理請(qǐng)求過程中,Woker 最多不超過 200 個(gè)。我們可以通過配置 conf/server.xml 中 Connector 的 minSpareThreads 和 maxThreads 對(duì)這兩個(gè)屬性進(jìn)行定制。
          2. Pollor 用于檢測(cè)已就緒的 Socket。默認(rèn)最多不超過 2 個(gè),Math.min(2,Runtime.getRuntime().availableProcessors());。我們可以通過配置 pollerThreadCount 來定制。
          3. Acceptor 用于接受新連接。默認(rèn)是 1 個(gè)。我們可以通過配置 acceptorThreadCount 對(duì)其進(jìn)行定制。

          Requtst Process

          Acceptor

          1. Acceptor 在啟動(dòng)后會(huì)阻塞在 ServerSocketChannel.accept(); 方法處,當(dāng)有新連接到達(dá)時(shí),該方法返回一個(gè) SocketChannel。
          2. 配置完 Socket 以后將 Socket 封裝到 NioChannel 中,并注冊(cè)到 Poller,值的一提的是,我們一開始就啟動(dòng)了多個(gè) Poller 線程,注冊(cè)的時(shí)候,連接是公平的分配到每個(gè) Poller 的。NioEndpoint 維護(hù)了一個(gè) Poller 數(shù)組,當(dāng)一個(gè)連接分配給 pollers[index] 時(shí),下一個(gè)連接就會(huì)分配給 pollers[(index+1)%pollers.length].
          3. addEvent() 方法會(huì)將 Socket 添加到該 Poller 的 PollerEvent 隊(duì)列中。到此 Acceptor 的任務(wù)就完成了。

          Poller

          1. selector.select(1000)。當(dāng) Poller 啟動(dòng)后因?yàn)?selector 中并沒有已注冊(cè)的 Channel,所以當(dāng)執(zhí)行到該方法時(shí)只能阻塞。所有的 Poller 共用一個(gè) Selector,其實(shí)現(xiàn)類是 sun.nio.ch.EPollSelectorImpl
          2. events() 方法會(huì)將通過 addEvent() 方法添加到事件隊(duì)列中的 Socket 注冊(cè)到 EPollSelectorImpl,當(dāng) Socket 可讀時(shí),Poller 才對(duì)其進(jìn)行處理
          3. createSocketProcessor() 方法將 Socket 封裝到 SocketProcessor 中,SocketProcessor 實(shí)現(xiàn)了 Runnable 接口。worker 線程通過調(diào)用其 run() 方法來對(duì) Socket 進(jìn)行處理。
          4. execute(SocketProcessor) 方法將 SocketProcessor 提交到線程池,放入線程池的 workQueue 中。workQueue 是 BlockingQueue 的實(shí)例。到此 Poller 的任務(wù)就完成了。

          Worker

          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 的映射關(guān)系。映射關(guān)系會(huì)保留到 org.apache.catalina.connector.Request 中,Container 處理階段 request.getHost() 是使用的就是這個(gè)階段查詢到的映射主機(jī),以此類推 request.getContext()、request.getWrapper() 都是。

          Container

          • 需要注意的是,基本上每一個(gè)容器的 StandardPipeline 上都會(huì)有多個(gè)已注冊(cè)的 Valve,我們只關(guān)注每個(gè)容器的 Basic Valve。其他 Valve 都是在 Basic Valve 前執(zhí)行。
          • request.getHost().getPipeline().getFirst().invoke() 先獲取對(duì)應(yīng)的 StandardHost,并執(zhí)行其 pipeline。
          • request.getContext().getPipeline().getFirst().invoke() 先獲取對(duì)應(yīng)的 StandardContext,并執(zhí)行其 pipeline。
          • request.getWrapper().getPipeline().getFirst().invoke() 先獲取對(duì)應(yīng)的 StandardWrapper,并執(zhí)行其 pipeline。
          • 最值得說的就是 StandardWrapper 的 Basic Valve,StandardWrapperValve
          1. allocate() 用來加載并初始化 Servlet,值的一提的是 Servlet 并不都是單例的,當(dāng) Servlet 實(shí)現(xiàn)了 SingleThreadModel 接口后,StandardWrapper 會(huì)維護(hù)一組 Servlet 實(shí)例,這是享元模式。當(dāng)然了 SingleThreadModel在 Servlet 2.4 以后就棄用了。
            createFilterChain() 方法會(huì)從 StandardContext 中獲取到所有的過濾器,然后將匹配 Request URL 的所有過濾器挑選出來添加到 filterChain 中。
            doFilter() 執(zhí)行過濾鏈,當(dāng)所有的過濾器都執(zhí)行完畢后調(diào)用 Servlet 的 service() 方法。

            參考:

          https://www.amazon.com/How-Tomcat-Works-Budi-Kurniawan/dp/097521280X
          http://product.dangdang.com/25084132.html
          https://tomcat.apache.org/tomcat-9.0-doc/index.html
          http://www-eu.apache.org/dist/tomcat/tomcat-9/v9.0.0.M22/src/
          http://gearever.iteye.com/blog/1844203


          感謝您的閱讀,也歡迎您發(fā)表關(guān)于這篇文章的任何建議,關(guān)注我,技術(shù)不迷茫!小編到你上高速。


              · END ·
          最后,關(guān)注公眾號(hào)互聯(lián)網(wǎng)架構(gòu)師,在后臺(tái)回復(fù):2T,可以獲取我整理的 Java 系列面試題和答案,非常齊全


          正文結(jié)束


          推薦閱讀 ↓↓↓

          1.不認(rèn)命,從10年流水線工人,到谷歌上班的程序媛,一位湖南妹子的勵(lì)志故事

          2.如何才能成為優(yōu)秀的架構(gòu)師?

          3.從零開始搭建創(chuàng)業(yè)公司后臺(tái)技術(shù)棧

          4.程序員一般可以從什么平臺(tái)接私活?

          5.37歲程序員被裁,120天沒找到工作,無奈去小公司,結(jié)果懵了...

          6.IntelliJ IDEA 2019.3 首個(gè)最新訪問版本發(fā)布,新特性搶先看

          7.漫畫:程序員相親圖鑒,笑屎我了~

          8.15張圖看懂瞎忙和高效的區(qū)別!

          一個(gè)人學(xué)習(xí)、工作很迷茫?

          點(diǎn)擊「閱讀原文」加入我們的小圈子!

          瀏覽 23
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产第1页| 天天澡天天狠天干天 | 成人网站在线进入 | 亚洲无码家庭乱伦 | 美女操逼国产欧美亚洲色 |