通过源码学Netty-业务逻辑

前言

经过了服务启动,建立连接,接收数据,接下来就是要执行业务逻辑了,这一回,我们就来看看Netty是怎么操作业务逻辑的

开始

首先明确一点,操作业务逻辑的前序流程和接收数据其实是一样的,不同之处在于操作业务逻辑是通过fireChannelread方法传播出去之后开始处理,之前我们碰到了fireChannelread方法后都是去找到headContext看源码,其实fireChannelread的调用者是ChannelPipeline,而ChannelPipeline里又是由一个个的ChannelHandler组成,ChannelHandler也不是能直接执行的,而是由ChannelhannelHandlerContext来实现的。

 从图上看,pipeline有两个流向,分别是从外向内的流向和从内向外的流向,对应的是读数据和写数据,又叫入站Inbound和出站Outbound,可以看到图中有一个个的处理器,注意,要理解Inbound和Outbound,不能用传统IO中的In代表输入,Out代表输出来看待,Inbound的含义是不是应用内部主动请求的事件,比如读取数据读取完这个事件,本身不是应用内部发起的,所以是InboundHandler,反过来读取数据本身这个操作就是一个OutBoundHandler。

ChannelPipeline在传播事件时,会判断ChannelPipeline中的下一个handler类型是不是和事件本身的运动方向相匹配,如果不匹配则会跳过该handler前进到下一个,在这里我们需要处理业务逻辑需要实现的是InboundHandler。

 接下来我们来看源码,在这里我们首先套用上一次讲接收数据的流程,把断点打在NioEventLoop的unsafe.read方法上,先启动server,再启动client,然后断点进入方法,一直执行到pipeline.fireChannelRead(readBuf.get(i));这个方法,继续下一步执行,到了io.netty.channel.AbstractChannelHandlerContext#invokeChannelRead(io.netty.channel.AbstractChannelHandlerContext, java.lang.Object)

static void invokeChannelRead(final AbstractChannelHandlerContext next, Object msg) {
        final Object m = next.pipeline.touch(ObjectUtil.checkNotNull(msg, "msg"), next);
        //这个executor就是NioEventLoop
        EventExecutor executor = next.executor();
        if (executor.inEventLoop()) {
            //执行ChannelRead
            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,并且在继续传播
                ((ChannelInboundHandler) handler()).channelRead(this, msg);
            } catch (Throwable t) {
                invokeExceptionCaught(t);
            }
        } else {
            fireChannelRead(msg);
        }
    }

继续往下走,走到io.netty.channel.AbstractChannelHandlerContext#fireChannelRead这个方法

@Override
    public ChannelHandlerContext fireChannelRead(final Object msg) {
        //这里的findContextInbound方法,就是寻找下一个可以执行ChannelRead的处理器
        invokeChannelRead(findContextInbound(MASK_CHANNEL_READ), msg);
        return this;
    }

继续

 private AbstractChannelHandlerContext findContextInbound(int mask) {
        AbstractChannelHandlerContext ctx = this;
        EventExecutor currentExecutor = executor();
        do {
            ctx = ctx.next;
        } while (skipContext(ctx, currentExecutor, mask, MASK_ONLY_INBOUND));//这里判断了下一个Handler是不是能执行channelRead
        return ctx;
    }

 于是返回到EchoServerHandler中,示例代码的EchoServerHandler确实是继承了ChannelInboundHandlerAdapter,也重写了ChannelRead方法,所以确实有资格处理

@Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        //这是官方示例代码,实际应用中业务逻辑代码就写在这个地方
        ctx.write(msg);
    }

总结

总结一下,1.Netty中处理业务逻辑的本质就是在pipeline中所有handler的ChannelRead的执行过程,2.默认处理线程是Channel绑定的NioEventLoop线程,也可以用pipeline.addLast来修改pipeline,3.handler的处理中途可以退出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值