handler的执行顺序是怎么样的

100次阅读
没有评论

共计 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 网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-08-16发表,共计2426字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)