Pipeline是一个链式结构,pipeline中的每个节点是一个ChannelHandlerContext对象,每个context节点保存了它包裹的执行器 ChannelHandler ,节点之间通过双向链表连接
在创建一个Pipeline的时候会创建对应的HeadContext以及TailContext去处理边缘的事件,所有用户定义的Handler都会夹在Head和Tail中间
在调用addXXX去增加一个ChannelHandler的时候其核心代码如下:
public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
final AbstractChannelHandlerContext newCtx;
synchronized (this) {
// 1.检查是否有重复handler
checkMultiplicity(handler);
// 2.创建节点
newCtx = newContext(group, filterName(name, handler), handler);
// 3.添加节点
addLast0(newCtx);
}
// 4.回调用户方法
callHandlerAdded0(handler);
return this;
}
其中简单地使用synchronized防止多线程并发操作双向链表
-
检查是否有重复的handler:netty使用一个成员变量added标识一个channel是否已经添加,如果当前要添加的Handler是非共享的,并且已经添加过(添加到别的Pipeline中去过),那就抛出异常,否则,标识该handler已经添加
-
创建DefaultChannelHandlerContext并包含对应的Handler
-
添加节点就是一个简单地双向链表插入操作
-
通过调用ctx.handler().handerAdded(ctx)来回调handlerAdded方法
在事件处理以及传递过程中,inBound事件从head节点传播到tail节点,outBound事件从tail节点传播到head节点,最后都会交由边缘的Head和Tail绑定的Unsafe去处理底层操作,NioServerSocketChannel对应NioMessageUnsafe, NioSocketChannel对应NioByteUnsafe,除此之外异常传播会通过调用notifyHandlerException(t)往后传播,而且不分inbound还是outbound节点,不像outBound事件一样会往前传播,因此ExceptionHandler一般都放在末尾