Netty篇:ChannelPipeline與ChannelHandler源碼分析


概述


???????上面幾篇文章中會經(jīng)??吹綀?zhí)行到某個地方,然后就開始在ChannelPipeline傳播事件,再由ChannelPipeline責(zé)任鏈上的一個個ChannelHandler去處理,所以ChannelPipeline和ChannelHandler才是用戶真正處理各種業(yè)務(wù)的地方,主要包括:數(shù)據(jù)包編解碼,業(yè)務(wù)處理,數(shù)據(jù)包寫入通道。

???????每個Channel都會維護(hù)一個ChannelPipeline,而ChannelPipeline其實(shí)是包含頭尾指針的雙向鏈表,里邊的的每個節(jié)點(diǎn)都是由ChannelHandler封裝成的ChannelHandlerContext上下文,ChannelHandlerContext中除了封裝ChannelHandler還包含了一些所關(guān)聯(lián)的組件實(shí)例。

???????ChannelHandler處理器分為兩大類:一類是ChannelInboundHandler通道入站處理器,一類是ChannelOutboundHandler通道出站處理器,均繼承自ChannelHandler接口。兩個接口都有自己的處理適配器,分別是ChannelInboundHandlerAdapter和ChannelOutboundHandlerAdapter,實(shí)現(xiàn)自己的業(yè)務(wù)只需繼承這兩個適配器即可。

???????入站事件在ChannelPipeline中由頭指針向尾指針傳播,只處理Inbound類型的Handler,出站事件由尾指針向頭指針傳播,只處理Outbound類型的Handler。貼張官方注釋的圖:


在這里插入圖片描述


ChannelPipeline添加節(jié)點(diǎn)


???????前面文章已經(jīng)分析過了,Channel初始化時會初始化一個ChannelPipeline,初始化代碼如下:

在這里插入圖片描述

???????綁定所屬的Channel,聲明一個succeededFuture和voidPromise用來處理異步操作。然后創(chuàng)建TailContext類型的尾指針,HeadContext的頭指針,將其串成鏈表。TailContext和HeadContext都繼承自AbstractChannelHandlerContext,內(nèi)部維護(hù)了unsafe的對象。

???????ChannelPipeline提供了一系列增刪ChannelHandler節(jié)點(diǎn)的方法,此處以最常用的addLast為例:

在這里插入圖片描述

???????首先檢查Handler是否重復(fù)添加,然后創(chuàng)建一個DefaultChannelHandlerContext對象封裝目標(biāo)handler,并將相關(guān)聯(lián)的組件添加進(jìn)去。然后進(jìn)入addLast0將其加入鏈表:

在這里插入圖片描述

???????將獲得的DefaultChannelHandlerContext插入鏈表的尾部,尾結(jié)點(diǎn)的上一個位置。然后回到主方法,判斷此時Channel是否注冊到EventLoop,如果沒有則新增一個任務(wù)注冊后添加,如果已經(jīng)注冊,判斷是不是當(dāng)前線程是不是EventLoop線程,將其添加到任務(wù)隊(duì)列中,啟動線程后執(zhí)行。如果已經(jīng)注冊且為EventLoop線程則直接觸發(fā)HandlerAdd事件。



ChannelPipeline事件傳播




???????ChannelPipeline的事件傳播主要從調(diào)用fireIN_EVET()方法開始,此處以常用的fireChannelRead()為例:

在這里插入圖片描述

???????調(diào)用上下文DefaultChannelHandlerContext的invekeChannelRead方法,將數(shù)據(jù)和ChannelPipeline的頭結(jié)點(diǎn)傳入:

在這里插入圖片描述

???????獲取當(dāng)前context所綁定的EventLoop線程,然后判斷當(dāng)前線程是否是綁定的EventLoop線程,是則直接執(zhí)行invokeChannelRead方法,不是則封裝成任務(wù)放到任務(wù)隊(duì)列中,等待線程輪詢執(zhí)行,然后進(jìn)入invokeChannelRead方法:

在這里插入圖片描述

???????判斷是否需要執(zhí)行handler,需要則獲取handler執(zhí)行其channelRead,否則繼續(xù)向下傳播。因?yàn)榇藭r是頭結(jié)點(diǎn),進(jìn)入其channelRead方法,直接就向下傳播:


在這里插入圖片描述

???????進(jìn)入context的傳播方法如下:


在這里插入圖片描述

???????在findContextInbound()方法中尋找下一個handler如下:

在這里插入圖片描述

???????然后又進(jìn)入了invokeChannelRead方法,進(jìn)入了傳播循環(huán):

在這里插入圖片描述

???????當(dāng)不再調(diào)用
ctx.fireChannelRead(msg)向下傳播時,傳播停止,或者當(dāng)傳播到尾結(jié)點(diǎn)是,釋放資源,結(jié)束傳播,尾結(jié)點(diǎn)channelRead如下:

在這里插入圖片描述

在這里插入圖片描述

在這里插入圖片描述



???????Outbound事件發(fā)生時,會觸發(fā)Outbound類型handler,流程相似,區(qū)別是從尾節(jié)點(diǎn)開始,向頭結(jié)點(diǎn)傳播。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容