tomcat 發(fā)展多年,成熟而穩(wěn)定, 但是在當今最新求快的 java web 技術棧中,這種優(yōu)秀的中間件卻與我們漸行漸遠。
靜下心來學習 , 賞析大牛們是如何設計和架構一個優(yōu)秀的中間件系統(tǒng),如有錯誤,共同探討,共同學習。
宏觀架構
tomcat 的啟動流程: startup.sh -> catalina.sh start ->java -jar org.apache.catalina.startup.Bootstrap.main()
先上小圖,一圖以避之,看個大概。

所有組件:
1.server: 一個tomcat實例
2.service: 處理即將到來的socket服務
3.connector : socket 連接器 , http協(xié)議的轉化
4.container : 加載管理servlet 并處理request
其中核心組件 為connector, container
預備知識 :
- tomcat組件實現(xiàn)了lifeCyle接口 生命周期方法為: init-> start -> stop-> destroy
- tomcat組件繼承了lifeCyleBase 抽象類
- lifeCyleBase 抽象類 中實現(xiàn)了 lifeCycle接口的方法, 并且個主鍵在調用相應的生命周期方法會調用內部的 initInternal startInternal stopInternal destroyInternal 方法
關于組件的初始化 啟動 停止 銷毀 我們后續(xù)探討。
connector
-
構造函數(shù)初始化
image.png
connector 是通過此構造器創(chuàng)建的【上層如何創(chuàng)建這個對象 ,我們后續(xù)再說】
看一下 ProtocolHandler 的創(chuàng)建過程




到這里已明白, protocolHandler 默認使用Http11NioProtocol .
Http11NioProtocol 對象創(chuàng)建時候 屬性 endpoint 被賦值為 NioEndpoint 對象。
Http11NioProtocol handler 屬性設置為 ConnectionHandler
Endpoint handler 屬性設置為 ConnectionHandler
- 初始化init
a> 創(chuàng)建 CoyoteAdapter 并注冊到protocolHandler 中

b> protocolHandler 【即 構造函數(shù)初始化 分析的Http11NioProtocol 】初始化, 先看下ProtocolHandler 的體系圖。


初始化過程:
Http11NioProtocol.init()->AbstractHttp11Protocol.init()->AbstractProtocol.init()
即子類初始化調用父類初始化。
在 AbstractProtocol.init() 中 endpoint 初始化:

c.endpoint初始化
看下endpint 的類繼承關系

類: NioEndpoint 方法 init()

類: AbstractEndpoint 方法: init()

類: NioEndpoint 方法 : bind()

類: NioEndpNioEnoint 方法 : initServerSocket()

3.啟動start() 方法
類 : Connector 方法 : startInternal()

類 : AbstractProtocol 方法: start()

類: NioEndpNioEnoint 方法 : startInternal()

我們分析下紅色箭頭 3,4 中的創(chuàng)建 poller 線程 和 acceptor 線程的作用是什么?
先看Accetpor 線程:
1.實現(xiàn)了runnable 接口 ,在run()方法中:


再看poller 線程:

Abs


至此,Acceptor跑在一個單獨的線程里,它在一個死循環(huán)里調用 accept方法來接收新連接,一旦有新的連接請求到來,accept方法返回一個 Channel 對象,接著把 Channel對象交給 Poller 去處理。
Poller 的本質是一個 Selector,也跑在單獨線程里。Poller在內部維護一個 Channel數(shù)組,它在一個死循環(huán)里不斷檢測 Channel的數(shù)據(jù)就緒狀態(tài),一旦有 Channel可讀,就生成一個 SocketProcessor任務對象扔給 Executor去處理。
我們來看下processSocket方法是如何處理socketWrapper的?
類: AbstractEndpoint 方法 : processSocket

看下SocketProcessor類的作用
類: NioEndpoint.SocketProcessor
創(chuàng)建:

看下繼承關系:

當使用線程池執(zhí)行的時候,活執(zhí)行父類SocketProcessorBase 的run()方法 ,父類的run()方法 會調用子類SocketProcessor的doRun()方法。
類: NioEndpoint.SocketProcessor 方法 : doRun()

我們知道在創(chuàng)建Http11NioProtocol 對象的同時 ,創(chuàng)建了NioEndpoint ,并給NioEndpoint 設置handler 屬性為 ConnectionHandler , 我們看下
ConnectionHandler 的 process 方法。


會調用Http11NioProtocol 的 createProcessor方法 創(chuàng)建 Http11Processor 對象 http11Processor繼承關系如下 :

AbstractProcessorLight類中 的process() 方法

子類: Http11Processor 的service()方法

我們知道在 Connector組件初始化的時候 給protocolHandler設置了adapter屬性,如下:

也就是說: getAdapter().servcive(req , rep) 交給了CoyoteAdapter 適配器來處理。

自此, connector 組件如何處理一個socket 請求,分析完畢
總結:
1.一個connector組件 可分為 protocolHandler 和 Adapter ,protocolHandler 用于處理 網絡請求 , Adapter 將內部request , response 適配成 servlet的HttpServletReqeust , HttpServiceResponse
protocolHandler主要處理 網絡連接 和 應用層協(xié)議 ,包含了兩個重要部件 EndPoint 和 Processor, EndPoint 是用來實現(xiàn) TCP/IP 協(xié)議數(shù)據(jù)讀寫的,本質調用操作系統(tǒng)的 socket 接口 , Processor用于處理socket, 轉換應用層協(xié)議 ,封裝內部 request 和 response
adapter 用于 內部 request 和 response 轉換 成sevlet 規(guī)范的 HttpServletReqeust , HttpServiceResponse
-
EndPoint 一圖以避之
image.png -
Processor 用來實現(xiàn) HTTP 協(xié)議,Processor 接收來自 EndPoint 的 Socket,讀取字節(jié)流解析成 Tomcat Request 和 Response 對象,并通過 Adapter 將其提交到容器處理,Processor 是對應用層協(xié)議的抽象
image.png
最后簡圖總結下:



