Pipeline初始化
在Netty中一个Channel对应一个Pipeline,在AbstractChannel的构造函数中会进行Pipeline的构造,
默认会创建两个Context,一个是HeadContext,链表头结点,一个是TailContext,链表尾结点。HeadContext和TailContext都是一个ChannelHandlerContext
protected DefaultChannelPipeline(Channel channel) { this.channel = ObjectUtil.checkNotNull(channel, "channel"); succeededFuture = new SucceededChannelFuture(channel, null); voidPromise = new VoidChannelPromise(channel, true); tail = new TailContext(this); head = new HeadContext(this); head.next = tail; tail.prev = head; }
添加ChannelHandler
在Netty中主要有两种Handler,一种是InboundHandler和OutBoundHandler。两种handler的关系如下。
在DefaultChannelPipeline的addLast方法中执行添加Handler的逻辑。
1. 判断Handler之前是否添加过
private static void checkMultiplicity(ChannelHandler handler) { if (handler instanceof ChannelHandlerAdapter) { ChannelHandlerAdapter h = (ChannelHandlerAdapter) handler; if (!h.isSharable() && h.added) { throw new ChannelPipelineException( h.getClass().getName() + " is not a @Sharable handler, so can't be added or removed multiple times."); } h.added = true; } }
2. 把Hanler封装成Context对象
newCtx = newContext(group, filterName(name, handler), handler);
3. 添加进Context链表中
private void addLast0(AbstractChannelHandlerContext newCtx) { AbstractChannelHandlerContext prev = tail.prev; newCtx.prev = prev; newCtx.next = tail; prev.next = newCtx; tail.prev = newCtx; }
3. 执行handlerAdd的回调
EventExecutor executor = newCtx.executor(); if (!executor.inEventLoop()) { callHandlerAddedInEventLoop(newCtx, executor); return this; } } callHandlerAdded0(newCtx);
删除ChannelHandler
在DefaultChannelPipeline中执行remove逻辑,也就是从context链表中删除该handler对应的Context。回调删除方法。
private AbstractChannelHandlerContext remove(final AbstractChannelHandlerContext ctx) { assert ctx != head && ctx != tail; synchronized (this) { atomicRemoveFromHandlerList(ctx); // If the registered is false it means that the channel was not registered on an eventloop yet. // In this case we remove the context from the pipeline and add a task that will call // ChannelHandler.handlerRemoved(...) once the channel is registered. if (!registered) { callHandlerCallbackLater(ctx, false); return ctx; } EventExecutor executor = ctx.executor(); if (!executor.inEventLoop()) { executor.execute(new Runnable() { @Override public void run() { callHandlerRemoved0(ctx); } }); return ctx; } } callHandlerRemoved0(ctx); return ctx; }
InBound事件传播
ChannelInBound的事件传播是从上到下的传播,当用户读请求进来时会根据addLast的Handler的顺序进行往下传播
在HeadContext中读事件的回调如下:
public ChannelHandlerContext fireChannelRead(final Object msg) { invokeChannelRead(findContextInbound(MASK_CHANNEL_READ), msg); return this; }
当找下一个InBound时会从Head开始找。找完后回调channelRead方法。
private AbstractChannelHandlerContext findContextInbound(int mask) { AbstractChannelHandlerContext ctx = this; EventExecutor currentExecutor = executor(); do { ctx = ctx.next; } while (skipContext(ctx, currentExecutor, mask, MASK_ONLY_INBOUND)); return ctx; }
OutBound的事件传播
OutBound的事件传播刚好与InBound的相反,他是根据addLast相反的顺序进行传播。
在findContextOutbound方法中,是从TailContext开始调用。
private AbstractChannelHandlerContext findContextOutbound(int mask) { AbstractChannelHandlerContext ctx = this; EventExecutor currentExecutor = executor(); do { ctx = ctx.prev; } while (skipContext(ctx, currentExecutor, mask, MASK_ONLY_OUTBOUND)); return ctx; }
异常传播
异常传播跟addLast填入顺序一致
@Override public ChannelHandlerContext fireExceptionCaught(final Throwable cause) { invokeExceptionCaught(findContextInbound(MASK_EXCEPTION_CAUGHT), cause); return this; }