注:本文只關注於請求執行順序,無初始化過程
高層執行鏈
瀏覽器—>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內部,執行完過濾器鏈纔會執行