美文网首页程序员
netty源码分析(20)- 删除ChannelHandler过

netty源码分析(20)- 删除ChannelHandler过

作者: Jorgezhong | 来源:发表于2019-02-28 10:03 被阅读0次

    上一节学习了添加ChannelHandler的过程了解了,也明白了添加handler是如何促发handlerAdded事件。其中还包括了ChannelInitializer这样特殊的handler,在完成了添加handler的任务后,就从pipeline中删除了。

    本节研究删除ChannelHandler的逻辑。类似ChannelInitializer这种,handler用完一次就没什么用的场景,类似权限校验,每次新连接接入需要校验权限,之后的数据传输就不需要了,这时候就可以动态的删掉权限校验的handler。如下

    class DataServerInitializer extends ChannelInitializer<SocketChannel> {
    
        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
    
            ch.pipeline().addLast(
                            new AuthHandler(),
                            new DataServerHandler()
                    );
        }
    }
    
    
    class AuthHandler extends SimpleChannelInboundHandler<ByteBuf> {
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, ByteBuf password) throws Exception {
            //校验密码
            if (pass(password)) {
                //校验通过,后续不需要继续校验,删除该handler
                ctx.pipeline().remove(this);
            }else {
                ctx.close();
            }
        }
    
        private boolean pass(ByteBuf password) {
            //ignore: 校验逻辑
            return false;
        }
    }
    

    ChannelHandler是背ChannelHanderContext包装起来的。因此,删除ChannelHandler过程如下:

    1. 找到handler对应的ChannelHandlerContext
    2. 从链表中删除ChannelHandlerContext
    3. 触发handlerRemoved事件
        @Override
        public final ChannelPipeline remove(ChannelHandler handler) {
            //先获取ChannelHandlerContext再删除
            remove(getContextOrDie(handler));
            return this;
        }
    
    • getContextOrDie()找到handler对应的ChannelHandlerContext
        private AbstractChannelHandlerContext getContextOrDie(ChannelHandler handler) {
            //获取ChannelHandlerContext,没有则抛异常
            AbstractChannelHandlerContext ctx = (AbstractChannelHandlerContext) context(handler);
            if (ctx == null) {
                throw new NoSuchElementException(handler.getClass().getName());
            } else {
                return ctx;
            }
        }
    
    
        @Override
        public final ChannelHandlerContext context(ChannelHandler handler) {
            //handler为空则抛异常
            if (handler == null) {
                throw new NullPointerException("handler");
            }
            //从链表头开始遍历到尾,直到,直到找到对应的handler对应的ctx
            AbstractChannelHandlerContext ctx = head.next;
            for (;;) {
    
                if (ctx == null) {
                    return null;
                }
    
                if (ctx.handler() == handler) {
                    return ctx;
                }
    
                ctx = ctx.next;
            }
        }
    
    • 先删除,再调用callHandlerRemoved0触发handlerRemoved事件
        private AbstractChannelHandlerContext remove(final AbstractChannelHandlerContext ctx) {
            //断言,非头也非尾
            assert ctx != head && ctx != tail;
    
            synchronized (this) {
                //将ctx从pipeline链表中删除
                remove0(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() {
                            //触发HandlerRemoved事件
                            callHandlerRemoved0(ctx);
                        }
                    });
                    return ctx;
                }
            }
            //触发HandlerRemoved事件
            callHandlerRemoved0(ctx);
            return ctx;
        }
    
    • 从链表中删除
        private static void remove0(AbstractChannelHandlerContext ctx) {
            //链表删除,修改两端的前后节点
            AbstractChannelHandlerContext prev = ctx.prev;
            AbstractChannelHandlerContext next = ctx.next;
            prev.next = next;
            next.prev = prev;
        }
    
    
    • 触发handlerRemoved事件。该动作获取了handler并调用了回调函数handlerRemoved(),最后修改了handler状态,标记已经完成了删除。
        private void callHandlerRemoved0(final AbstractChannelHandlerContext ctx) {
            // Notify the complete removal.
            try {
                //调用ctx的触发事件方法
                ctx.callHandlerRemoved();
            } catch (Throwable t) {
                fireExceptionCaught(new ChannelPipelineException(
                        ctx.handler().getClass().getName() + ".handlerRemoved() has thrown an exception.", t));
            }
        }
    
        final void callHandlerRemoved() throws Exception {
            try {
                // Only call handlerRemoved(...) if we called handlerAdded(...) before.
                if (handlerState == ADD_COMPLETE) {
                    //获取handler并触发事件回调函数
                    handler().handlerRemoved(this);
                }
            } finally {
                // Mark the handler as removed in any case.
                //标记handler已经删除
                setRemoved();
            }
        }
    
        final void setRemoved() {
            //修改handler状态为完成删除
            handlerState = REMOVE_COMPLETE;
        }
    
    

    相关文章

      网友评论

        本文标题:netty源码分析(20)- 删除ChannelHandler过

        本文链接:https://www.haomeiwen.com/subject/covcuqtx.html