Netty之Pipeline
- 不管時Netty客戶端和服務端,都出現了Pipeline的身影
- 從之前的學習可以大致瞭解到
- 在Netty中每個Channel都有且僅有一個ChannelPipeline與之對應
官方解釋
- ChannelPipeline註釋,從註釋中對ChannelPipeline有了進一步的認識
- 在ChannelPipeline中存放了ChannelHandler列表,用來處理或攔截出站和入站事件。這些在一個Channel對象中完成
- 每一個Channel擁有自己的ChannelPipeline,當Channel對象被創建的時候,隨之創建
ChannelPipeline結構
- 通過ChannelPipeline的構造方法進行跟蹤,在DefaultChannelPipeline中完成初始化
- 通過代碼可以發現,ChannelPipeline中維護了一個由ChannelHandlerContext組成的雙向鏈表
- 鏈表尾部和頭部分別是 TailContext 和 HeadContext
- 並且每一個 ChannelHandlerContext 又關聯這一個 ChannelHandler
- 可以理解爲 每一個 tail 或 head 關聯着一個 ChannelHandler
- 通過圖更能清晰地看出其結構
- 接下來HeadContext和TailContext的類結構圖
- 從類結構圖中可以發現 Head 和 Tail 都實現了 ChannelHandlerContext 和 ChannelHandler
- 並且它們的初始化操作都是在 AbstractChannelHandlerContext 中完成的
- HeadContext 和 TailContext 初始化
- 可以發現Head初始化的時候outbound屬性爲true,而Tail初始化inbound屬性爲true
- 即Head是一個OutBound對象,而Tail是一個InBound對象
ChannelHandler和ChannelPipeline關聯
- 無論是客戶端和服務端,都使用到了 AbstractBootstrap 的 handler 或 childHandler 方法
- 我們可以在其中添加自定義Handler,如下代碼示例
- 通過ChannelInitializer對象可以添加自定義Handler。addLast方法完成具體的添加操作,分爲以下幾個步驟
- 首先把傳入的 channelInitializer 對象進行包裝然後添加到鏈表中
- 向鏈表中添加我們的自定義handler,此時構造完成一個雙向鏈表
- 需要注意的是 ChannelInitializer 繼承了類 ChannelInboundHandlerAdapter
- 因此在鏈表中 除了 head 是 OutBound 其它節點全是 InBound (後續分析OutBound和InBound)
- 鏈表構建完成後,後續會對鏈表進行註冊遍歷,把Handler添加到Channel對應的Pipeline中
- 添加過程中移除最開始添加的ChannelInitializer
Pipeline事件傳播機制
- AbstractChannelHandlerContext 有 inbound 和 outbound 兩個變量用於標識 Context 對應的 handler 類型
- inbound -> true -> ChannelInboundHandler
- outbound -> true -> ChannelOutboundHandler
outbound事件傳播
- outbound事件都是請求事件,即接收到請求之後通過outbound事件進行通知
- 以客戶端發起connect請求爲例,最終調用到DefaultChannelPipeline的connect方法
- 由此可以發現,outbound事件是以tail爲起點開始傳播調用的
- 然後調用AbstractChannelHandlerContext的connect方法
- findContextOutbound方法—以當前context爲起點,向pipeline中的雙向鏈表尋找一個outbound屬性爲ture的節點
- 結合之前的學習過程,這裏實際上是傳遞到了head節點,因爲head節點的outbound屬性爲true
- 所以connect消息傳遞給head後,會將消息傳遞給對應的ChannelHandler處理
- 最終connect方法在DefaultChannelPipeline的connect方法中由 unsafe 處理目標請求
- 處理邏輯流程圖(該圖片引用自咕泡學院Tom老師的課堂筆記)
inbound事件傳播
-
inbound事件與outbound事件的處理方式類似,只是方向不同。即 head -> customContext -> tail
-
outbound事件都是請求事件,而inbound則是通知事件
-
inbound事件一般發生在Channel的狀態改變或IO事件的就緒
-
處理邏輯流程圖(圖片引用自咕泡學院Tom老師的課堂筆記)
- 觀察DefalutChannelPipeline的channelActive方法可以發現其channelActive方法是空的
- 因爲inbound事件需要用戶實現自定義的處理器
Handler深入
- 每一個ChannelHandler都會有一個ChannelHandlerContext與之關聯
- ChannelHandlerContext允許ChannelHandler之間實現交互
- ChannelHandlerContext、ChannelHandler、ChannelPipeline的關係
與之關聯
- ChannelHandlerContext允許ChannelHandler之間實現交互
- ChannelHandlerContext、ChannelHandler、ChannelPipeline的關係