netty处理器链读数据执行流程源码分析

参考资料

netty处理器链初始化源码分析

触发读事件

//NioEventLoop的run方法
//这个是事件轮训线程的轮训方法,会轮训处理相应的事件,比如读事件
protected void run() {
    for (;;) {
                try {
                   //获取到Selector上的io事件
                    processSelectedKeys();
                } finally {
                    // Ensure we always run tasks.
                    final long ioTime = System.nanoTime() - ioStartTime;
                    runAllTasks(ioTime * (100 - ioRatio) / ioRatio);
                }
    }
}

轮训读取通道数据,触发处理器链

//NioByteUnsafe的read方法
//通过channel的unsafe去读取数据
@Override
    public final void read() {
        //省去不需要代码
      
       // 1.轮训读取通道数据
      // 2.将读取到的数据放到处理器链中处理
        try {
            do {
                byteBuf = allocHandle.allocate(allocator);
                allocHandle.lastBytesRead(doReadBytes(byteBuf));
                if (allocHandle.lastBytesRead() <= 0) {
                    // nothing was read. release the buffer.
                    byteBuf.release();
                    byteBuf = null;
                    close = allocHandle.lastBytesRead() < 0;
                    break;
                }

                allocHandle.incMessagesRead(1);
                readPending = false;
                //读取到数据,通过处理器链进行部分数据处理
                pipeline.fireChannelRead(byteBuf);
                byteBuf = null;
            } while (allocHandle.continueReading());

          //省去不需要代码
}

处理器链执行流程

//DefaultChannelPipeline的fireChannelRead方法
//pipeline的一个触发处理器链的方法,是处理器链入口,从头结点开始处理
public final ChannelPipeline fireChannelRead(Object msg) {
    //触发处理器链,因为是读取,所以从头结点开始
    AbstractChannelHandlerContext.invokeChannelRead(head, msg);
    return this;
}

//AbstractChannelHandlerContext的三个方法,是迭代处理器链关键的三个方法

//fireChannelRead方法用于迭代下一个处理器,根据findContextInbound方法
//我们在自定义的处理器中,在处理结尾也要触发当前处理器的这个方法,这样才能放行
//执行下一个处理器
@Override
    public ChannelHandlerContext fireChannelRead(final Object msg) {
        invokeChannelRead(findContextInbound(), msg);
        return this;
    }

//invokeChannelRead方法用于一个新处理器的入口,会调用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);
      }
    });
  }
}

//invokeChannelRead方法用于真正回调当前处理器的实现方法
private void invokeChannelRead(Object msg) {
  if (invokeHandler()) {
    try {
      ((ChannelInboundHandler) handler()).channelRead(this, msg);
    } catch (Throwable t) {
      notifyHandlerException(t);
    }
  } else {
    fireChannelRead(msg);
  }
}

总结

1.轮训读取通道数据,每次都是部分数据,到处理器中的数据可能会有粘包和半包问题

2.处理器链非常强大,扩展性也很强,有利于实现不同的处理器的功能,对处理器进行分层实现,这样我们整个处理器链将会变得非常强大

3.这里只是分析了读方法,数据是由通道底层进入的,如果是写方法,那么数据是由我们传递到通道底层,这个顺序是相反的,相对应处理器链调用顺序也是一样

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值