中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何實現Tomcat請求處理

發布時間:2022-01-12 17:31:41 來源:億速云 閱讀:222 作者:柒染 欄目:服務器

這篇文章跟大家分析一下“如何實現Tomcat請求處理”。內容詳細易懂,對“如何實現Tomcat請求處理”感興趣的朋友可以跟著小編的思路慢慢深入來閱讀一下,希望閱讀后能夠對大家有所幫助。下面跟著小編一起深入學習“如何實現Tomcat請求處理”的知識吧。

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

繪制圖形使用的工具是 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 支持等等。

Overview

如何實現Tomcat請求處理

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

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

  2. Poller 線程組。用于監聽 Socket 事件,當 Socket 可讀或可寫等等時,將 Socket 封裝一下添加到 worker  線程池的任務隊列中。

  3. worker 線程組。用于對請求進行處理,包括分析請求報文并創建 Request 對象,調用容器的 pipeline 進行處理。

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

Connector Init and Start

如何實現Tomcat請求處理
  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

如何實現Tomcat請求處理
  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

如何實現Tomcat請求處理
  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

如何實現Tomcat請求處理
  • 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

如何實現Tomcat請求處理
  • 需要注意的是,基本上每一個容器的 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() 方法。

關于如何實現Tomcat請求處理就分享到這里啦,希望上述內容能夠讓大家有所提升。如果想要學習更多知識,請大家多多留意小編的更新。謝謝大家關注一下億速云網站!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

县级市| 凌云县| 太仆寺旗| 乌兰浩特市| 柘荣县| 鄂托克旗| 林口县| 玉溪市| 吉安市| 永仁县| 玉环县| 渝中区| 额敏县| 枞阳县| 屯昌县| 阿拉善左旗| 永兴县| 南部县| 龙陵县| 尉犁县| 措美县| 安陆市| 临澧县| 河池市| 鹤峰县| 潜山县| 宁晋县| 迁西县| 达孜县| 治县。| 昆山市| 华阴市| 宜章县| 客服| 江永县| 柳河县| 五家渠市| 松溪县| 岚皋县| 财经| 资溪县|