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

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
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值