Netty processor chain read data execution process source code analysis

Reference

Netty processor chain initialization source code analysis

Trigger read event

//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);
                }
    }
}

Read channel data in rotation and trigger the processor chain

//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());

          //省去不需要代码
}

Processor chain execution flow

//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);
  }
}

to sum up

1. Read the channel data in rotation, each time it is part of the data, and the data to the processor may have problems with sticky packets and half packets

2. The processor chain is very powerful and extensible, which is conducive to the realization of the functions of different processors and the layered realization of the processors, so that our entire processor chain will become very powerful

3. Here is just an analysis of the read method. The data is entered from the bottom of the channel. If it is the write method, then the data is passed to the bottom of the channel by us. This sequence is reversed, and the corresponding processor chain call sequence is the same

Guess you like

Origin blog.csdn.net/weixin_38312719/article/details/108720683