ChannelPipeline
單看名稱就可以知道Channel
的管道。本篇將結合它的預設實現類DefaultChannelPipeline
來對它做一個簡單的介紹。
示例圖
上圖是官方提供的ChannelPipeline
的事例圖。IO請求經由ChannelOutboundHandler
中ChannelOutboundHandler
處理之後寫出到服務端,服務接收到讀入後,由ChannelInboundHandler
依次處理。
下面來看下DefaultChannelPipeline
的類圖:
DefaultChannelPipeline
實現了ChannelPipeline
介面,而ChannelPipeline
又繼承了ChannelInboundInvoker
、ChannelOutboundInvoker
和Iterable
。
ChannelInboundInvoker
:發起對ChannelPipeline
中下一個ChannelInboundHandler
的方法的呼叫。
ChannelOutboundInvoker
:發起對ChannelPipeline
中下一個ChannelOutboundHandler
的方法的呼叫。
Iterable
:可遍歷ChannelPipeline
中的ChannelHandler
。
NioEventLoop
繼承自SingleThreadEventLoop
,而SingleThreadEventLoop
又繼承自SingleThreadEventExecutor
。
SingleThreadEventExecutor
內部持有一個Thread物件,是Netty
多執行緒的基礎。
可以認為, 一個NioEventLoop
與一個特定的執行緒進行了繫結,並且在其生命週期內,繫結的執行緒都不會再改變。
DefaultChannelPipeline
DefaultChannelPipeline
的主要工作就是對ChannelHandler
的管理,包括ChannelHandler
的增減,事件的觸發等。
ChannelHandler
的增減
以addFirst
方法為例:
public final ChannelPipeline addFirst(EventExecutorGroup group, String name, ChannelHandler handler) {
final AbstractChannelHandlerContext newCtx;
synchronized (this) {
// 檢查handler是否可以共享
checkMultiplicity(handler);
// 給AbstractChannelHandlerContext起個獨立的名字
name = filterName(name, handler);
// 建立DefaultChannelHandlerContext
newCtx = newContext(group, name, handler);
// 執行實際的新增操作
addFirst0(newCtx);
// channel尚未註冊到eventloop
if (!registered) {
// 設定newCtx的狀態為ADD_PENDING
newCtx.setAddPending();
// 設定過一會回撥ChannelHandler的handlerAdded方法
callHandlerCallbackLater(newCtx, true);
return this;
}
EventExecutor executor = newCtx.executor();
if (!executor.inEventLoop()) {
newCtx.setAddPending();
executor.execute(new Runnable() {
@Override
public void run() {
callHandlerAdded0(newCtx);
}
});
return this;
}
}
callHandlerAdded0(newCtx);
return this;
}
複製程式碼
addFirst
方法先檢查新增的ChannelHandler
是否可以共享(判斷共享的方法是對於每個channel當前ChannelHandler是否需要不同的狀態),再建立ChannelHandler
的上下文關係,使ChannelHandler
以連結串列方式存在於ChannelPipeline
中。當ChannelHandler
新增成功後,再呼叫ChannelHandler
的handlerAdded
方法。其它的新增方式和addFirst
類似。
事件觸發
以fireChannelActive
方法為例:
public final ChannelPipeline fireChannelActive() {
AbstractChannelHandlerContext.invokeChannelActive(head);
return this;
}
複製程式碼
從HeadContext
的head開始,依次觸發下一個ChannelHandler
的channelActive
方法。
本篇簡單介紹了ChannelPipeline
的相關概念,當ChannelHandler
介紹完後,再具體介紹ChannelPipeline
中的HeadContext
和TailContext
。
文中帖的程式碼註釋全在:KAMIJYOUDOUMA, 有興趣的童鞋可以關注一下。
本篇到此結束,如果讀完覺得有收穫的話,歡迎點贊、關注、加公眾號【貳級天災】,查閱更多精彩歷史!!!