共计 2426 个字符,预计需要花费 7 分钟才能阅读完成。
本篇内容主要讲解“handler 的执行顺序是怎么样的”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让丸趣 TV 小编来带大家学习“handler 的执行顺序是怎么样的”吧!
为了说明这个问题我们增加了 2 个 encoder,分别是 MavlinkMsg2BytesEncoder 和 FixLengthEncoder,作用分别是将一个协议对象转化为 byte 数组,另一个是为了客户端解析的方便,增加了一个定长的设置。
还是按照老方法,设置断点,然后查看其调用顺序。
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 的执行顺序是怎么样的”有了更深的了解,不妨来实际操作一番吧!这里是丸趣 TV 网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!