pipeline.fireChannelRead
原理图
源码分析一ChannelPipeline.fireChannelRead
调用invokeChannelRead,传入headContext 指定线程为io线程还是handler自身业务线程
public final ChannelPipeline fireChannelRead ( Object msg) {
AbstractChannelHandlerContext . invokeChannelRead ( head, msg) ;
return this ;
}
static void invokeChannelRead ( final AbstractChannelHandlerContext next, final Object msg) {
ObjectUtil . checkNotNull ( msg, "msg" ) ;
EventExecutor executor = next. executor ( ) ;
if ( executor. inEventLoop ( ) ) {
next. invokeChannelRead ( msg) ;
} else {
executor. execute ( new Runnable ( ) {
@Override
public void run ( ) {
next. invokeChannelRead ( msg) ;
}
} ) ;
}
}
如果channel已经添加到责任链上,则执行channelRead
private void invokeChannelRead ( Object msg) {
if ( invokeHandler ( ) ) {
try {
( ( ChannelInboundHandler ) handler ( ) ) . channelRead ( this , msg) ;
} catch ( Throwable t) {
notifyHandlerException ( t) ;
}
} else {
fireChannelRead ( msg) ;
}
}
源码分析一SimpleChannelInboundHandler
判断消息是否为SimpleChannelInboundHandler指定泛型 是指定泛型触发处理【开发人员于channelRead0手动调用ctx.fireChannelRead(msg)】 不是指定泛型触发下一个入站handler处理 对于bytebuf通过引用计数算法释放内存
public void channelRead ( ChannelHandlerContext ctx, Object msg) throws Exception {
boolean release = true ;
try {
step- 1 : 判断消息是否为SimpleChannelInboundHandler < I > 指定泛型
if ( acceptInboundMessage ( msg) ) {
@SuppressWarnings ( "unchecked" )
I imsg = ( I ) msg;
step- 1.1 : 是指定泛型触发处理
channelRead0 ( ctx, imsg) ;
} else {
step- 1.2 : 不是指定泛型触发下一个入站handler处理
release = false ;
ctx. fireChannelRead ( msg) ;
}
} finally {
如果是ReferenceCounted 类型 则通过引用计数算法释放内存
if ( autoRelease && release) {
ReferenceCountUtil . release ( msg) ;
}
}
}
调用链路与线程原理图
左边为channel实际初始化后形成的handler链 每一个context都持有一个handler与线程[如果没有则使用workerEventLoop线程] 通过SINGLE_EVENTEXECUTOR_PER_GROUP参数可以使得所有context的业务线程被指定为同一个线程 context分为inbound和outbound两类,inbound处理入站消息,outbound处理出站消息
总结
当IO事件通过eventLoop线程处理后,会通过netty unsafe触发netty框架的链式处理,handler链可以使用自带线程,如无线程配置则使用workereventLoop线程 如果使用自带线程,推荐配置SINGLE_EVENTEXECUTOR_PER_GROUP参数使得每一个handlercontext线程相同
方法名 描述 ctx.fireChannelRead(msg) 从当前ctx开始寻找链式handler的下一个节点 ctx.pipeline().fireChannelRead(msg) 从链首开始调用,pipeline本身持有的也是headContext ctx.channel().write(msg) 调用pipeline.write, 从链尾开始出站 ctx.pipeline().write(msg) 从链尾开始出站 ctx.write(msg) 逆向查找下一个出站context