美文网首页
netty笔记-Pipeline的事件触发

netty笔记-Pipeline的事件触发

作者: 兴浩 | 来源:发表于2018-07-12 14:29 被阅读28次

    1. DefaultChannelPipeline的 fireChannelRead事件

    DefaultChannelPipeline中事件的触发是通过fire开头的方法来触发,其内部调用了AbstractChannelHandlerContext的相关的invoke静态方法

        @Override
        public final ChannelPipeline fireUserEventTriggered(Object event) {
            AbstractChannelHandlerContext.invokeUserEventTriggered(head, event);
            return this;
        }
    
        @Override
        public final ChannelPipeline fireChannelRead(Object msg) {
            AbstractChannelHandlerContext.invokeChannelRead(head, msg);
            return this;
        }
    
        @Override
        public final ChannelPipeline fireChannelReadComplete() {
            AbstractChannelHandlerContext.invokeChannelReadComplete(head);
            return this;
        }
    

    2. invokeChannelRead静态方法

    invokeChannelRead静态方法实际上是调用了AbstractChannelHandlerContext的invokeChannelRead实例方法

        static void invokeChannelRead(final AbstractChannelHandlerContext next, Object msg) {
            final Object m = next.pipeline.touch(ObjectUtil.checkNotNull(msg, "msg"), next);
            EventExecutor executor = next.executor();
            if (executor.inEventLoop()) {
                next.invokeChannelRead(m);
            } else {
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        next.invokeChannelRead(m);
                    }
                });
            }
        }
    

    3. invokeChannelRead实例方法

    调用了handler()的channelRead方法

        private void invokeChannelRead(Object msg) {
            if (invokeHandler()) {
                try {
                    ((ChannelInboundHandler) handler()).channelRead(this, msg);
                } catch (Throwable t) {
                    notifyHandlerException(t);
                }
            } else {
                fireChannelRead(msg);
            }
        }
    

    3.1 HeadContext

    HeadContext实现了Handler接口,所以handler方法就返回其自己,最终调用的是HeadContext的channelRead方法

     final class HeadContext extends AbstractChannelHandlerContext
                implements ChannelOutboundHandler, ChannelInboundHandler {
    
            @Override
            public ChannelHandler handler() {
                return this;
            }
    
            @Override
            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                ctx.fireChannelRead(msg);
            }
    }
    

    4. AbstractChannelHandlerContext的fireChannelRead事件

        @Override
        public ChannelHandlerContext fireChannelRead(final Object msg) {
            invokeChannelRead(findContextInbound(), msg);
            return this;
        }
    

    这个环节应该看起来跟DefaultChannelPipeline的 fireChannelRead事件是很相似的,不同点在于这里调用的对象是findContextInbound()

    4.1 findContextInbound

        private AbstractChannelHandlerContext findContextInbound() {
            AbstractChannelHandlerContext ctx = this;
            do {
                ctx = ctx.next;
            } while (!ctx.inbound);
            return ctx;
        }
    

    由于AbstractChannelHandlerContext是一个链表结果,其通过next寻找下个对象,所以next找到的对象应该是 1243这个引用对象

    5. 触发ChannelInboundHandler事件

    public class EchoServerHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            // 将消息记录到控制台
            ByteBuf in = (ByteBuf) msg;
            System.out.println( "Server received: " + in.toString(CharsetUtil.UTF_8));
            // 将接收到的消息写给发送者,而不冲刷出站消息
            ctx.write(in);
        }
    }
    

    完整的堆栈流程信息

    6.ChannelInvoker的实现

    实现ChannelInboundInvoker和ChannelOutboundInvoker的类有2种

    1. ChannelHandlerContext
    2. ChannelPipeline

    7.ChannelPipeline和ChannelHandlerContext的关系

    • DefaultChannelPipeline内部维护着ChannelHandlerContext链表关系,并且可以获取到Channel的信息
    • ChannelHandlerContext对Channel和Handler起到了承上启下的作用,在初始时同同时可以获取Pipeline和Handler的信息,由于可以获取到Pipeline的信息,那么同时就可以获取到Channel的信息,从此可知ChannelHandlerContext可获取的信息是非常丰富的,也符合其ChannelHandlerContext类的定义

    7.1DefaultChannelHandlerContext的初始化

        private AbstractChannelHandlerContext newContext(EventExecutorGroup group, 
    String name, ChannelHandler handler) {
            return new DefaultChannelHandlerContext(this, childExecutor(group), name, handler);
        }
        DefaultChannelHandlerContext(
                DefaultChannelPipeline pipeline, 
    EventExecutor executor, String name, ChannelHandler handler) {
            super(pipeline, executor, name, isInbound(handler), isOutbound(handler));
            if (handler == null) {
                throw new NullPointerException("handler");
            }
            this.handler = handler;
        }
        AbstractChannelHandlerContext(DefaultChannelPipeline pipeline, 
    EventExecutor executor, String name,
                                      boolean inbound, boolean outbound) {
            this.name = ObjectUtil.checkNotNull(name, "name");
            this.pipeline = pipeline;
            this.executor = executor;
            this.inbound = inbound;
            this.outbound = outbound;
            ordered = executor == null || executor instanceof OrderedEventExecutor;
        }
    

    参考:
    https://www.jianshu.com/p/4848729baf94

    相关文章

      网友评论

          本文标题:netty笔记-Pipeline的事件触发

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