pipeline的初使化
- pipeline的創建:pipeline在創建channel(無論是客服端的channel還是服務端的channel)的時候被創建。
- Netty裏目前只有一個pipeline的實現, 也就是DefaultChannelPipeline,構造方法如圖:
- 在Netty裏,業務邏輯是以寫對應的ChannelHandler來實現的,在Netty的內部,會將ChannelHandler封裝成ChannelHandlerContext對象,然後以鏈表的雙鏈表的形式進行組織。AbstractChannelHandlerContext部分代碼如下:
- 在pipeline裏有head和tail兩個屬性,分別指向channelHandlerContext的頭結點和尾結點,其中HeadContext內部有unsafe對象,可以通過unsafe處理讀寫事件。代碼如下:
- TailContext的inbound屬性設置爲true
添加ChannelHandler
DefaultChannelPipeline提供了往鏈表裏增加節點的方法,增加一個ChannelHandler包括如下幾個步驟- 判斷是否重複添加
- 創建節點並添加到雙鏈表中
- 回調添回完成事件
刪除ChannelHandler
刪除channleHandler的入口如下圖:- 找結點
- 刪除結點
- 回調事件
事件與異常的傳播
channelHandler在大類上可以分爲InboundHandler與outboundHandler。類圖如下:
我們在寫業務方法的時候,可以通過pipeline對象fire某個事件,也可以用ChannelHandlerContext 對象fire某個事件。兩種方式都會進行事件的傳播,兩個的區別是通過pipeline fire的事件是從雙鏈表的頭結點開始傳播的,而通過ChannelHandlerContext對象是從當前結點往下傳播 的read事件的傳播分析(Inbound事件)
當連接監聽到有OP_READ事件後,會調用unsafe的read方法進行處理,下面來看看unsafe是如何處理事件的。
- 處理channel read的入口
- pipeline觸發read的入口
- 調用head的invokeChannelRead方法
- 最終會調用到channelHandler的channelRead方法
- head結點的處理邏輯
- 找到下一個類型爲inbound的channelHandler
- 尾結點的處理邏輯,如果消息沒處理,則會打個warm日誌,並釋放bytebuf對象
write事件的傳播分析(Outbound事件)
在寫業務ChannelHandler的時候,如果是outbound類型的handler,可以重寫write方法,並通過ChannelHandlerContext對象調用write,讓write進行傳播,其中通過channel調用的write方法會從pipeline的tail結點開始傳播,而直接調用ChannelHandlerContext的write方法會從當前結點進行傳播。下面分析write事件如何在pipeline裏進行傳播
- 事件傳播的入口
-
tail結點write處理邏輯
- 找到前一個結點的處理邏輯
- 調用handler的witer方法
- 通過head結點的write方法,調用channel的unsafe對象,執行寫入操作
異常的傳播
當channelHandler在處理業務的時候發生了異常,異常信息會從當前的鏈上往下傳播,直到有一個channelHandler把異常處理了,如果沒有channelHandler把異常處理,會傳播到tail結點,在實際業務中,在channelHandler鏈的最後增加一個統一的異常處理下面分析異常的傳播流程
- 異常傳播入口
- 會調用到invokeExceptionCaught方法
- 調用到hander的exceptionCaught方法
- 在channelHandlerAdapter裏,默認會讓exception往下傳播
- AbstractChannelHandlerContext異常傳播的邏輯,先當前結點的下一個結點
- 傳到tail結點的邏輯