温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

handler的执行顺序是怎么样的

发布时间:2021-12-16 16:43:54 来源:亿速云 阅读:330 作者:iii 栏目:云计算

本篇内容主要讲解“handler的执行顺序是怎么样的”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“handler的执行顺序是怎么样的”吧!


为了说明这个问题我们增加了2个encoder,分别是MavlinkMsg2BytesEncoder和FixLengthEncoder,作用分别是将一个协议对象转化为byte数组,另一个是为了客户端解析的方便,增加了一个定长的设置。
还是按照老方法,设置断点,然后查看其调用顺序。

handler的执行顺序是怎么样的

NettyServerHandler.messageReceived是我们接收下行消息的终点,我们直接在这里来执行消息的返回。

首先进入NioSocketChannel.write方法,下面是代码

@Override
    public ChannelFuture write(Object msg) {
        return pipeline.write(msg);
    }

write方法定义在AbstractChannel当中,是netty当中所有的channel类的祖先。

在这个方法当中,开始执行依次执行pipeline当中的各个handler

下面是DefaultChannelPipeline.write方法

@Override
    public ChannelFuture write(Object msg) {
        return tail.write(msg);
    }

如果没有记错的话,下行的过程当中,是从head.fireChannelRead开始的,而在上行的过程当中,是从tail开始的,而实际上,head和tail是pipeline在初始化的时候默认生成的双向链表的头尾节点,他们并不完成任何实际工作。这里从tail开是上行的过程,应该说是非常符合逻辑的。

下一步我们看DefaultChannelHandlerContext.write方法

@Override
    public ChannelFuture write(Object msg, ChannelPromise promise) {
        DefaultChannelHandlerContext next = findContextOutbound(MASK_WRITE);
        next.invoker.invokeWrite(next, msg, promise);
        return promise;
    }

这里也是之前我们分析过的代码,查找双向链表当中prev节点。

之后是ChannelHandlerInvokerUtil.invokeWriteNow方法,

public static void invokeWriteNow(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
        try {
            ctx.handler().write(ctx, msg, promise);
        } catch (Throwable t) {
            notifyOutboundHandlerException(t, promise);
        }
    }

再然后是MessageToByteEncoder.write方法,

public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        ByteBuf buf = null;
        try {
            if (acceptOutboundMessage(msg)) {
                @SuppressWarnings("unchecked")
                I cast = (I) msg;
                if (preferDirect) {
                    buf = ctx.alloc().ioBuffer();
                } else {
                    buf = ctx.alloc().heapBuffer();
                }
                try {
                    encode(ctx, cast, buf);
                } finally {
                    ReferenceCountUtil.release(cast);
                }

                if (buf.isReadable()) {
                    ctx.write(buf, promise);
                } else {
                    buf.release();
                    ctx.write(Unpooled.EMPTY_BUFFER, promise);
                }
                buf = null;
            } else {
                ctx.write(msg, promise);
            }
        } catch (EncoderException e) {
            throw e;
        } catch (Throwable e) {
            throw new EncoderException(e);
        } finally {
            if (buf != null) {
                buf.release();
            }
        }
    }

这里分配一个动态缓冲区,然后调用encoder方法。

                if (preferDirect) {
                    buf = ctx.alloc().ioBuffer();
                } else {
                    buf = ctx.alloc().heapBuffer();
                }

请注意这段代码,这里的概念是指,当前缓冲区的分配是从系统io当中来分配,还是从jvm的堆当中来分配,2种方式各有利弊,将来我们会专门介绍这个问题。

在最后就是我们的encode方法了。

protected void encode(ChannelHandlerContext ctx, MAVLinkMessage msg, ByteBuf out) throws Exception {
        MAVLinkPacket packet = msg.pack();
        byte[] buf = packet.encodePacket();
        out.writeBytes(buf);
    }

而后续的encoder的调用过程基本跟前面大同小异。这里就不再赘述了。

到此,相信大家对“handler的执行顺序是怎么样的”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI