5. Netty中pipline与handler

Netty是基于Reactor模式的高性能网络框架,其主要是基于bossgroup和workergroup实现了主从Reactor模式,其中handler的调用链让用户自己定义对应的I/O处理逻辑,而这其中pipline是很重要的一环。在Netty Server端,每个Channel都会在初始化的时候都会实例化一个DefaultChannelPipeline与之进行绑定,这个pipline中保存着handler的处理链。
AbstractChannel(NioServerSocketChannel和NioSocketChannel都是它的子类)进行初始化的时候,会将一个pipline初始化,并与自身绑定。

protected AbstractChannel(Channel parent) {
        this.parent = parent;
        id = newId();
        unsafe = newUnsafe();
        pipeline = newChannelPipeline();
    }
     protected DefaultChannelPipeline newChannelPipeline() {
        return new DefaultChannelPipeline(this);
    }

当我们在服务端启动的时候增加handler的时候:

.childHandler(new ChannelInitializer<SocketChannel>()
{
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception
{
socketChannel.pipeline().addLast("hello world hanlder",new HelloWorldHandler());
}
}

,实际上是将handler加入到了NioSocketChannel的pipline的hanler链表上。(NioServerSocketChannel可以通过handler方法添加)

    public final ChannelPipeline addLast(String name, ChannelHandler handler) {
        return addLast(null, name, handler);
    }
    public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
        final AbstractChannelHandlerContext newCtx;
        synchronized (this) {
            checkMultiplicity(handler);
            newCtx = newContext(group, filterName(name, handler), handler);// 返回 DefaultChannelHandlerContext
            addLast0(newCtx);
            if (!registered) {
                newCtx.setAddPending();
                callHandlerCallbackLater(newCtx, true);
                return this;
            }
            EventExecutor executor = newCtx.executor();
            if (!executor.inEventLoop()) {
                callHandlerAddedInEventLoop(newCtx, executor);
                return this;
            }
        }
        callHandlerAdded0(newCtx);
        return this;
    }

    private void addLast0(AbstractChannelHandlerContext newCtx) {
        AbstractChannelHandlerContext prev = tail.prev;
        newCtx.prev = prev;
        newCtx.next = tail;
        prev.next = newCtx;
        tail.prev = newCtx;
    }

这里引申出另外一个点就是,在DefaultPipline中,默认有两个Handler节点,分别是headtail两个节点。

 protected DefaultChannelPipeline(Channel channel) {
        this.channel = ObjectUtil.checkNotNull(channel, "channel");
        succeededFuture = new SucceededChannelFuture(channel, null);
        voidPromise =  new VoidChannelPromise(channel, true);
        tail = new TailContext(this);
        head = new HeadContext(this);
        head.next = tail;
        tail.prev = head;
    }

这两个节点在整个handler调用链上有很大的作用,实际上上述代码可以发现,最终加入到pipline上的是通过封装后的DefaultChannelHandlerContext也就是我们经常说的上下文。DefaultChannelHandlerContext中包含有piplinehandler的引用,而pipline中含有channelcontext应用,形成了相互引用。
DefaultChannelHandlerContext实际上是对Handler进行了一个封装。
在这里插入图片描述
在其父类AbstractChannelHandlerContext,只有两个AbstractChannelHandlerContext引用:

volatile AbstractChannelHandlerContext next;
volatile AbstractChannelHandlerContext prev;

DefaultChannelPipeline中的HeadContextTailContext也是他的子类,我们常说的Netty中的handler链式处理实际上是通过AbstractChannelHandlerContext来实现了链式处理,并不是handler自己
一般我们在一个handler处理完之后,都建议调用ChannelHandlerContext.fireXXX将这个调用链路继续往后传递下去。我们以read为例说明,当读取完数据后会触发pipeline.fireChannelRead

 public final ChannelPipeline fireChannelRead(Object msg) {
        AbstractChannelHandlerContext.invokeChannelRead(head, msg);
        return this;
    }
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() {
                public void run() {
                    next.invokeChannelRead(m);
                }
            });
        }
    }
private void invokeChannelRead(Object msg) {
        if (invokeHandler()) {
            try {
                ((ChannelInboundHandler) handler()).channelRead(this, msg);
            } catch (Throwable t) {
                notifyHandlerException(t);
            }
        } else {
            fireChannelRead(msg);
        }
    }

这里首先传入的是HeadContext,可以看到,这里是会调用每个ChannelHandlerContextEventExecutor去执行具体任务(也就是worker线程组里面的线程),然后执行invokeChannelRead,这里首先会判断当前``ChannelHandlerContext是否加入到Handler执行链中,如果是,则执行对应Handler的channelRead,这里的handler()方法就是获取到ChannelHandlerContext中我们传入的Handler,这里开始传入的HeadContext:

// HeadContext
 public ChannelHandler handler() {
            return this;
        }

HeadContext中的handler()方法获取到就是他自己,也就是这里会执行HeadContext.channelRead:

 ctx.fireChannelRead(msg);

没有任何处理,直接调用了ChannelHandlerContext.fireChannelRead,在AbstractChannelHandlerContext中实现如下:

public ChannelHandlerContext fireChannelRead(final Object msg) {
        invokeChannelRead(findContextInbound(MASK_CHANNEL_READ), msg);
        return this;
    }

这里invokeChannelRead和上面的一样,但是findContextInbound就是找到下一个待执行的hanler:

 private AbstractChannelHandlerContext findContextInbound(int mask) {
        AbstractChannelHandlerContext ctx = this;
        do {
            ctx = ctx.next;
        } while ((ctx.executionMask & mask) == 0);
        return ctx;
    }

这里会根据刚才上面说的ChannelHandlerContext的链上每个ChannelHandlerContext 的executionMask 是否是给出的mask类型,那么这个怎么生成的呢,逻辑如下:

private static int mask0(Class<? extends ChannelHandler> handlerType) {
        int mask = MASK_EXCEPTION_CAUGHT;
        try {
            if (ChannelInboundHandler.class.isAssignableFrom(handlerType)) {
                mask |= MASK_ALL_INBOUND;

                if (isSkippable(handlerType, "channelRegistered", ChannelHandlerContext.class)) {
                    mask &= ~MASK_CHANNEL_REGISTERED;
                }
                if (isSkippable(handlerType, "channelUnregistered", ChannelHandlerContext.class)) {
                    mask &= ~MASK_CHANNEL_UNREGISTERED;
                }
                if (isSkippable(handlerType, "channelActive", ChannelHandlerContext.class)) {
                    mask &= ~MASK_CHANNEL_ACTIVE;
                }
                if (isSkippable(handlerType, "channelInactive", ChannelHandlerContext.class)) {
                    mask &= ~MASK_CHANNEL_INACTIVE;
                }
                if (isSkippable(handlerType, "channelRead", ChannelHandlerContext.class, Object.class)) {
                    mask &= ~MASK_CHANNEL_READ;
                }
                if (isSkippable(handlerType, "channelReadComplete", ChannelHandlerContext.class)) {
                    mask &= ~MASK_CHANNEL_READ_COMPLETE;
                }
                if (isSkippable(handlerType, "channelWritabilityChanged", ChannelHandlerContext.class)) {
                    mask &= ~MASK_CHANNEL_WRITABILITY_CHANGED;
                }
                if (isSkippable(handlerType, "userEventTriggered", ChannelHandlerContext.class, Object.class)) {
                    mask &= ~MASK_USER_EVENT_TRIGGERED;
                }
            }

            if (ChannelOutboundHandler.class.isAssignableFrom(handlerType)) {
                mask |= MASK_ALL_OUTBOUND;

                if (isSkippable(handlerType, "bind", ChannelHandlerContext.class,
                        SocketAddress.class, ChannelPromise.class)) {
                    mask &= ~MASK_BIND;
                }
                if (isSkippable(handlerType, "connect", ChannelHandlerContext.class, SocketAddress.class,
                        SocketAddress.class, ChannelPromise.class)) {
                    mask &= ~MASK_CONNECT;
                }
                if (isSkippable(handlerType, "disconnect", ChannelHandlerContext.class, ChannelPromise.class)) {
                    mask &= ~MASK_DISCONNECT;
                }
                if (isSkippable(handlerType, "close", ChannelHandlerContext.class, ChannelPromise.class)) {
                    mask &= ~MASK_CLOSE;
                }
                if (isSkippable(handlerType, "deregister", ChannelHandlerContext.class, ChannelPromise.class)) {
                    mask &= ~MASK_DEREGISTER;
                }
                if (isSkippable(handlerType, "read", ChannelHandlerContext.class)) {
                    mask &= ~MASK_READ;
                }
                if (isSkippable(handlerType, "write", ChannelHandlerContext.class,
                        Object.class, ChannelPromise.class)) {
                    mask &= ~MASK_WRITE;
                }
                if (isSkippable(handlerType, "flush", ChannelHandlerContext.class)) {
                    mask &= ~MASK_FLUSH;
                }
            }
            if (isSkippable(handlerType, "exceptionCaught", ChannelHandlerContext.class, Throwable.class)) {
                mask &= ~MASK_EXCEPTION_CAUGHT;
            }
        } catch (Exception e) {
            PlatformDependent.throwException(e);
        }
        return mask;
    }

其实就是判断当前ChannelHandlerContext 中的ChannelHandler是否有对应的方法,这里channelRead对应的就是MASK_CHANNEL_READ,也就是说,在fireChannelRead中会向后遍历ChannelHandlerContext ,如果有channelRead方法,那么就会执行对应的方法.
如果在执行方法最后调用了ChannelHandlerContext .fireChannelRead则会将这个调用链一直传递下去。

下面我们先以NioServerSocketChannel建立连接时pipline调用的逻辑处理为例来进行研究。当连接事件通知到来时会调用NioServerSocketChannel对应的pipline的 pipeline.fireChannelRead来进行相关处理。代码调用链如下:

//DefaultPipline中执行
 public final ChannelPipeline fireChannelRead(Object msg) {
        AbstractChannelHandlerContext.invokeChannelRead(head, msg);
        return this;
    }
    //会调用 HeadHandler
     @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) {
            ctx.fireChannelRead(msg);
        }

ctx.fireChannelRead(msg);实际上就是把事件往后续handler传递关键,如果自定义的实现里面没有显示的调用ctx.fireChannelRead(msg);则handler事件传播会到当前结束(一些coder会在其父类中显示的调用,以便事件得以继续传播)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值