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
最后簡圖總結下: