Tomcat執行鏈(從瀏覽器到Servlet)

注:本文只關注於請求執行順序,無初始化過程
高層執行鏈
瀏覽器—>http請求–>DNS服務–>三次握手–>tomcat處理–>四次揮手

DNS服務根據域名尋找ip
瀏覽器緩存–>系統緩存–>路由器緩存–>ISP DNS緩存–>DNS服務器

三次握手
客戶端、服務器交換並確認序列號(SYN/ACK)

四次揮手
客戶端、服務器雙向通知對方結束並確認

Tomcat處理(以Http11NioProtocol爲例)
監聽端口–>包裝Request–>轉發到Container–>Servlet

監聽端口
connector對象持有ProtocolHandler對象;ProtocolHandler持有AbstractEndpoint對象。AbstractEndpoint負責創建服務器套接字,並綁定到監聽端口
NioEndpoint.bind()綁定serverSock監聽端口
NioEndpoint
封裝底層網絡通信細節,提供基礎的網絡IO服務

Acceptor線程
負責監聽serverSock綁定的端口,即循環調用serverSock.accept()獲取SocketChannel對象
並將獲取到的SocketChannel對象封裝爲NioChannel對象,並交給Poller線程,將之加入到Poller同步事件隊列(PollerEvent隊列)
Poller線程
以較少的資源輪詢已經連接的套接字並保持連接,當數據可用時將之交給工作線程(而非每個套接字單獨綁定一個線程)
每個Poller線程有一個獨有的Selector對象(Selector與NioChannel的關係見NIO)
Poller線程會逐個調用PollerEvent線程對象的run()方法,將PollerEvent事件的IOChannel註冊到Selector上
再獲取Selector中所有已註冊的NioChannel對象,逐個執行processKey(SelectionKey, NioSocketWrapper)
在該方法中調用processSocket()方法,封裝爲SocketProcessor對象,丟到線程池ThreadPoolExecutor中執行

PollerEvent線程隊列
重寫run()方法不會在單獨線程中執行,而是Poller線程中逐個被同步調用
實現Runnable接口,只是用來表示一個輪詢事件
run()中將本PollerEvent事件的IOChannel註冊到Selector上

SocketProcessor線程
先檢查握手,再調用由ConnectionHandler抽象類定義的process()方法
接下來就是由不同協議定義的由socketWrapper轉換爲Request的具體算法(終於到Request了)
就是這個方法:org.apache.coyote.http11.Http11Processor#service(不想看)
然後這個service中,getAdapter().service(request, response);

CoyoteAdapter
連接Connector與Container的橋樑,轉換Request
並轉發到Container的管道上,逐級執行閥門,到底層StandardWrapperValve

StandardWrapperValve
封裝Servlet,先執行過濾器,再執行servlet
servlet.service(request, response)方法在ApplicationFilterChain內部,執行完過濾器鏈纔會執行

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章