handler的执行顺序是怎么样的
本篇内容主要讲解“handler的执行顺序是怎么样的”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“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的执行顺序是怎么样的”有了更深的了解,不妨来实际操作一番吧!这里是美国cn2网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!