1. 程式人生 > >Jetty9原始碼剖析 - Connector元件 - ManagedSelector

Jetty9原始碼剖析 - Connector元件 - ManagedSelector

轉載自ph0ly:http://www.ph0ly.com

一、概念

ManagedSelector是一個託管的Selector,它包裝了NIO中的Selector,並在內部完成select事件監聽處理

二、繼承體系

繼承體系

可以看到ManagedSelector是具有生命週期的,繼承體系比較簡單

三、總體架構

總體架構

圖中綠色表示ManagedSelector相關的元件,其中EPC內綠色部分屬於ManagedSelector內部的類SelectorProducer,ManagedSelector啟動的時候會執行ExecutionStrategy.execute,讓EPC開始執行,而在EPC內部會執行ManagedSelector內部類的SelectorProducer來執行相關的select操作,完成讀寫事件的處理(EPC將會在後面講解)

四、原始碼剖析

1. 建構函式

建構函式

建構函式比較簡單,strategy預設使用SelectorProducer來作為生產者,這個類是ManagedSelector的內部類,ExecutionFactory預設會建立ExecuteProduceConsume,即EPC作為任務執行器

2. 啟動

啟動

啟動很簡單,開一個新的Selector,newSelector實際就是Selector.open呼叫,然後將當前ManagedSelector扔到SelectorManager的Executor裡面執行

run方法

可以看到ManagedSelector提供的run方法其實就是執行了ExecuteProduceConsume.execute,讓EPC開始執行生產消費任務

3. 連線處理與事件註冊

Accept動作

前面的SelectorManager其實已經講解到了選擇了一個ManagedSelector後,會使用ManagedSelector.submit方法,將上圖中的Accept動作放到_actions列表執行,這個將會被後續的EPC利用SelectorProducer執行拿到,就會執行Accept.run方法,可以看到是首先註冊了一個0的interestOps,也就是什麼也不監聽(為啥這裡註冊為0?其實這裡對於Jetty來說,很多東西都還沒準備好,例如EndPoint和Connection都沒建好,所以暫時並不能處理資料的讀寫,因此不監聽事件),之後再向_actions提交一個CreateEndPoint的動作,開始建立EndPoint

CreateEndPoint類

createEndPoint方法

run方法可以看到是執行createEndPoint,使用了SelectorManager來建立EndPoint和Connection,前面SelectorManager已經講解過了,這裡不再贅述
之後會將EndPoint關聯上Connection,EndPoint顧名思義其實就是端點,端點需要和連線打通,這樣才能形成真正意義上的一條資料通道
selectionKey.attach會將當前的這個SocketChannel的SelectionKey關聯上這個創建出來的EndPoint

之後觸發SelectorManager的端點完成操作、連線完成操作
在端點完成操作裡面會將當前的SelectionKey的interestOps切換為OP_READ,註冊上讀事件,這樣後續就能處理讀資料
在連線完成操作裡面會將當前Connection的回撥註冊到EndPoint的_fillInterest,也就是說當資料到來時會觸發這個_fillInterest的回撥,從而呼叫到HttpConnection的onFillable,這樣就打通了端點事件到連線的資料操作(EndPoint和Connection將在後續章節詳細講解)

4. 資料讀寫

SelectorProducer.produce

EPC會呼叫生產者生產任務,也就是這裡的SelectorProducer.produce,生產完成後,會根據分派型別(dispatch)來執行任務,通常是在同一個執行緒執行任務,如果dispatch是要求新的執行緒,才會放到另一個執行緒,下一節會詳細講解EPC的執行邏輯,這裡不再多講

首先看produce方法,他會執行我們之前畫的圖中的幾個步驟,分別是:processSelected、runActions、update、select

SelectorProducer.processSelected

SelectorProducer.processSelected

processSelected會判斷看當前是否有準備好的事件,如果當前有事件發生,則判斷是否是SelectableEndPoint,也就是是否是讀寫事件,如果是讀寫事件會觸發SelectableEndPoint.onSelected(),通常就是我們的SelectChannelEndPoint執行(這個元件會在後續詳細講解),在它的onSelected會返回一個讀或者寫或者讀寫的任務

我們還可以看到其實它還可以處理連線的接入,這其實就是之前我們說的使用者指定ServerConnector的acceptors=0,就會讓ManagedSelector來執行接入

SelectorProducer.runActions

SelectorProducer.runChange

runActions會從_actions佇列拿到任務,然後執行,前面我們說的連線的接入時,會觸發submit一個Accept動作,這個動作就會被放到_actions佇列,讓這個EPC來執行

SelectorProducer.update

接下來是update的執行,update會拿到select出來的SelectionKey列表,然後去更新它們對應的感興趣的事件(詳細的會在EndPoint講解),例如當前需要寫入操作,後續會將這個SelectionKey的interestOps改成OP_WRITE,這樣就能寫入資料到Channel,當沒有資料寫入時會移除SelectionKey的OP_WRITE操作,這樣動態切換讀寫操作

SelectorProducer.select

select就是阻塞等待新的事件到來,如果Selector檢測Channel有事件發生或者被wakeup,這裡就會返回,並將發生事件的Channel的SelectionKey列表拿到,邏輯相對還是比較簡單

這就是SelectorProducer執行的核心邏輯,produce來生產任務,能完成事件檢測、讀寫切換、動作(連線、銷燬、關閉等等)執行

五、 總結

ManagedSelector邏輯也不算複雜,主要就是結合了EPC這個執行操作,讓原本簡單的事件檢測迴圈看起來很繞,不過靜下心來看,還是可以理解的。相信大部分讀者在讀到這篇文章的時候,對EPC感到困惑,EPC到底來幹什麼,按照常規的NIO玩法,不就是一個while迴圈+select操作就能完成的事情,在這裡被玩得這麼複雜了,這個答案將會在接下來的EPC章節講解,歡迎大家持續關注~