Tomcat最底層使用的是Java標準的SocketServer和Socket接受和處理請求,但是Socket接受到的資料是網路運輸層的TCP或UDP協議的資料,需要轉為Http或者其它應用層協議的資料,Tomcat中就是通過連接器Connector來管理Socket連接、決議Scoket請求為Request并封裝回應資料為Response物件,新版本的Tomcat容器使用的連接器是Coyote框架,本文會詳細介紹Connector的Coyote框架原理,本文很多內容參考了這篇博客
什么是Coyote
Coyote是Tomcat聯結器框架的名稱,是Tomcat服務器提供的供客戶端訪問的外部介面,客戶端通過Coyote與服務器建立鏈接、發送請求并且接收回應,
Coyote封裝了底層的網路通信(Socket請求以及回應處理),為Catalina容器提供了統一的介面,是Catalina容器與具體的請求協議以及 I/O方式解耦,Coyote將Socket輸入轉換為Request物件,交由Catalina容器進行處理,處理請求完成之后,Catalina通過Coyote提供的Response物件將結果寫入輸出流,
Coyote作為獨立的模塊,只負責具體協議和I/O的處理,與Servlet規范實作沒有直接關系,因此即便是Request和Response物件也并未實作Servlet規范對應的介面,而是在Catalina中將他們進一步封裝為ServletRequest何ServletResponse,

Coyote支持的協議
Coyote框架支持以下三種應用層協議:
- HTTP/1.1協議:這是絕大多數Web應用采用的訪問協議,主要用于Tomcat單獨運行(不予Web服務器集成)的情況,
- AJP協議:用于和Web服務器(如Apache HTTP Server)集成,以實作針對靜態資源的優化以及集群部署,當前支持AJP/1.3,
- HTTP/2.0協議:下一代HTTP協議,自Tomcat8.5以及9.0版本開始支持,截止目前,主流的最新版本均已支持HTTP/2.0,
針對HTTP和AJP協議,Coyote又按照 I/O方式分別提供了不同的選擇方案(自8.5/9.0版本起,Tomcat已出了對BIO的支持),
- NIO:采用Java NIO類別庫實作,
- NIO2:采用JDK 7最新的NIO2類別庫實作,
- APR:采用APR(Apache可移植運行庫)實作
在8.0之前,Tomcat默認采用的I/O方式為BIO,之后采用NIO,無論NIO、NIO2還是APR,在性能方面均優于以往的BIO,如果采用APR,甚至可以達到接近于 Apache HTTP Server的回應性能,
在Coyote中,HTTP/2.0的處理方式與HTTP/1.1和AJP不同,采用一種升級協議的方式實作,這也是有HTTP/2.0的傳輸方案決定的,
可以采用一種簡單的分層視圖來描述Tomcat對協議以及 I/O方式的支持,如下圖所示:

Connector的核心概念
在Connector中有如下幾個核心概念:
- Endpoint:Coyote通信端點,即通信監聽的介面,是具體的Socker接收處理類,是對傳輸層的抽象,Tomcat并沒有Endpoint介面,而是提供了一個抽象類AvstractEndpoint,根據I/O方式的不同,提供了NioEndpoint(NIO)、AprEndpoint(APR)以及Nio2Endpoint(NIO2)三個實作,
- Processor:Coyote協議處理介面,負責構造Request和Response物件,并且通過Adapter將其提交到Catalina容器處理,是對應用層的抽象,Processor是單執行緒的,Tomcat在同一次鏈接中復用Processor,Tomcat按照協議的不同提供了3個實作類:Http11Processor(HTTP/1.1)、AjpProcessor(AJP)、StreamProcessor(HTTP/2.0),除此之外,他還提供了兩個用于處理內部處理的實作:UpgradeProcessorInternal和UpgradeProcessorExternal,前者用于處理內部支持的升級協議(如HTTP/2.0和WebSocket),后者用于處理外部擴展的升級協議支持,
- UpgradeProtocol:Tomcat采用UpgradeProtocol介面表示HTTP升級協議,當前只提供了一個實作(Http2Protocol)用于處理HTTP/2.0.他根據請求創建一個用于升級處理的令牌UpgradeToken,該令牌中包含了具體的HTTP升級處理器HttpUpgradeHandler,HTTP/2.0的處理器實作為Http2UpgradeHandler,Tomcat中的WebSocket也是通過UpgradeToken機制實作的,
Connector請求處理流程

Connector處理請求的流程如上所示,我們一步步分析一下流程的內容:
- 當Connector啟動時,會同時啟動其持有的Endpoint實體,Endpoint并允許多個執行緒(有屬性acceptorThreadCount確定),每個執行緒允許一個AbstractEndpoint.Acceptor實體,在AbstractEndpoint.Acceptor實體中監聽埠通信(I/O方式不同,具體的處理方式也不同),而且只要Endpoint處于運行狀態,始侄訓圈監聽,
- 當監聽到請求時,Acceptor將Socker封裝為SocketWrapper實體(此時并未讀取資料),并交由一個SocketProcessor物件處理(此程序也由執行緒池異步處理),此部分根據I/O方式的不同處理會有所不同,如NIO采用輪詢的方式檢測SelectionKey是否就緒,如果就緒,則獲取一個有效的SocketProcessor物件并且提交執行緒池處理,
- SocketProcessor是一個執行緒池Worker實體,每一個I/O方式均有自己的實作,他首先判斷Socket的狀態(如完成SSL握手),然后提交到ConnectionHandler處理,
- ConnectionHandler是AbstractProtocol的一個內部類,主要用于鏈接選擇一個合適的Processor實作以進行請求處理,
- 提升性能,他針對每個有效的理解都會快取器Processor物件,不僅如此,當前鏈接關閉時,其Processor物件還會被釋放到一個回收佇列(升級協議不會回收),這樣后續鏈接可以重置并且重復利用,以減少物件構造,
- 在處理請求時,他首先會從快取中獲取當前鏈接的Processor物件,如果不存在,則嘗試根據協商協議構造Processor(如HTTP/2.0請求),如果不存在協商協議(如HTTP/1.1請求),則從回收佇列中獲取一個已釋放的Processor物件使用,如果回收佇列中沒有可用的物件,那么由具體的協議創建一個Processor使用(同時注冊到快取),
- 協議升級時,ConnectionHandler會從當前Processor得到一個UpgradeToken物件(如果沒有,則默認為HTTP/2),并構造一個升級Processor實體(如果是Tomcat支持的協議則會是UpgradeProcessorInternal,否則是UpgradeProcessorExternal)替換當前的Processor,并將當前的Processor釋放回收,替換后,該鏈接的后續處理將由升級Process完成,
- 通過UpgradeToken中HttpUpgradehandler物件的init()方法進行初始化,以便準備開始啟用新協議,
我是御狐神,歡迎大家關注我的微信公眾號:wzm2zsd

本文最先發布至微信公眾號,著作權所有,禁止轉載!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/300846.html
標籤:Java
下一篇:Quartz 定時任務管理類
