0
点赞
收藏
分享

微信扫一扫

netty4核心源码分析第八篇一核心篇服务端fireChannelRead责任链


文章目录

  • ​​pipeline.fireChannelRead​​
  • ​​原理图​​
  • ​​源码分析一ChannelPipeline.fireChannelRead​​
  • ​​源码分析一SimpleChannelInboundHandler​​
  • ​​调用链路与线程原理图​​
  • ​​总结​​

pipeline.fireChannelRead

原理图

netty4核心源码分析第八篇一核心篇服务端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




举报

相关推荐

0 条评论