参照
読み取りイベントをトリガーします
//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.これは読み取り方法の分析です。データはチャネルの下部から入力されます。書き込み方法の場合、データはチャネルの下部に渡されます。この順序は逆になり、対応するプロセッサチェーンの呼び出しシーケンスも同じです