Jetty源碼剖析系列(7) - 底層網絡通信的細節

我們先來回顧一下 Jetty 負責網絡連接的類 ServerConnector 的構造函數: 可以看到在ServerConnector的構造函數裏會創建一個 SelectorManager ,然後加到它的bean裏面(這裏其實體現了Jetty的一個設計模式,就是設計了一個containner,把相關的模塊放到這個containner裏面,啟動該container(調用doStart方法)就會連帶啟動裏面的模塊(調用模塊的doStart方法), Jetty裏面的Server,Connector都是這樣的containner。)

我們再來看newSelectorManager方法: 就是創建一個ServerConnectorManager對象,ServerConnectorManager繼承了SelectorManager類: ,我們再看一下SelectorManager的doStart方法: 可以看到在調用父類的doStart方法之前,會創建ManagedSelector,並將該selector加到SelectorManager的bean裏面,隨後再在調用父類的doStart方法時調用該selector的doStart方法,注意selector的數目是根據CPU的數量計算出來的, newSelector方法其實就是直接構建一個ManagedSelector對象: 我們看一下ManagedSelector的構造函數: 關於ManagedSelector,我在系列(4)裏面已經有詳細剖析。

此時我們先回過頭去看一下ServerConnector的doStart方法: 它先調用open方法打開ServerSocketChannel,這個我在系列(6)裏面有詳細剖析。我們這裏關注一下它調用的父類的doStart(AbstractConnector)方法: 它先調用了父類ConntainnerLifeCycle的doStart方法將它所擁有的bean(模塊)都啟動起來,其中就包括了我們前面加進去的SelectorManager,隨即也就會把SelectorManager裏面的ManagedSelector啟動起來(調用它的doStart方法)。到此,我們可以看到ServerConnector會先啟動Selector,然後再啟動Acceptor。Connector,Selector,Acceptor,這三者的關係我畫了下圖來説明: 從上圖可以看到,Acceptor負責接收網絡連接,封裝成一個channel,然後把該channel註冊到Selector,由selector來monitor這個channel的狀態是Readable還是Connectable還是Writable, 針對不同的狀態來做不同的事,比如readable的時候,也就是TCP的receive buffer裏面有發送給某個socket的數據時,tcp就會通知application來讀取。其實以上所説的這些,都是標準的NIO的操作,與編程語言無關,與容器框架也無關,而Jetty也只是實現了這個標準的NIO操作而已。

Acceptor實現了Runnable接口,它是被扔到QueuedThreadPool線程池裏面執行的:

Acceptor的run方法裏面循環調用了accept方法:

值得注意的是,serverChannel的accept方法調用是blocking的,就是説直到有一個connect請求過來它才會返回,當然,這個是可配置的(其實它就是在ServerConnection open這個serverChannel的時候就設置成blocking的了),當接收到一個connect請求後,返回一個socketChannel對象,然後就調用accepted方法,我們注意看accepted方法裏面最後那句, _manager.accept(channel) , 這個 _manager 就是我們上文説到的SelectorManager,我們再看它的accept方法: 到此,我們就清楚地看到Selector跟Accptor是如何聯繫到一起了,當然這裏的Selector是封裝後的Selector,我們先看一下它的submit方法: 這個方法核心的部分是這句: _updates.offer(update) , _updates 是一個 ArrayDeque<SelectorUpdate> ,就是説submit方法會把一個SelectorUpdate對象塞到一個Deque裏面,那我們再來看一下這個SelectorUpdate對象是什麼:

到此,我們先來總結一下,就是Acceptor接收到一個connect請求後,會封裝出一個Accept對象,這個對象實現了SelectorUpdate接口,然後把這個Accept對象塞到ManagedSelector的一個ArrayDeque裏面,其實這裏就是體現上文中的那個圖,接收到connect請求後,封裝好channel,交給Selector去monitor它的狀態,就是説接下來的事就由Selector來handle了,在看ManagedSelector的doStart方法前,我們先來回顧一下它的構造函數: 我們看到它把一個EatWhatYouKill對象加到它的bean裏面,那就意味着在啟動ManagedSelector時也會啟動這個EatWhatYouKill對象(調用它的doStart方法),同樣我們先來看一下EatWhatYouKill的構造函數: 一樣的套路,它把一個Producer對象加到它的bean裏面了,這個Producer是上ManagedSelector的構造函數裏面創建出來傳給EatWhatYouKill的構造函數的,SelectorProducer對象。

這個時候就可以來看一下ManagedSelector的doStart方法了: 它先調用的父類的doStart方法,其實就是去啟動它前面添加的beans(遞歸調用bean的doStart方法),然後通過 selectorManager的newSelector方法打開一個真正的Selector對象: 然後就通過線程池去執行了EatWhatYouKill的的produce方法(這裏用的是Java8的語法,而一個方法其實就是一段可執行的字節碼,自然是runnable的): 這裏核心的是tryProduce方法裏面循環調用的doProduce方法: 這個方法比較長,我們看核心的,先看它調用的produceTask方法是生產了什麼東西: 它調用的 producer的produce方法,_producer是上文提到的SelectorProducer對象,它的produce方法: (未完待續。。。。。。。)

關鍵詞:Jetty 源碼分析

相關推薦:

Tomcat NIO

Jetty源碼剖析系列(4)-Connector如何接收處理網絡請求

Tomcat 中的 NIO 源碼分析

學習Tomcat-六-Tomcat是如何接受連接

Tomcat9的Connector組件(二)

Tomcat 請求處理流程詳解

Jetty源碼剖析系列(3)-Connector如何接收處理網絡請求

《Netty權威指南》筆記

Netty(RPC高性能之道)原理剖析