Netty源码之Pipeline

在本文中我们将讲解pipeline的创建执行等,pipeline在很多地方都有这种概念,像是tomcat中,Spring的AOP中,都是通过链式调用一个一个的对传入的对象进行处理。

 pipeline = newChannelPipeline();

我们将从这行代码开始进行我们的源码之旅。

protected DefaultChannelPipeline newChannelPipeline() {
        return new DefaultChannelPipeline(this);
    }

直接创建了一个默认的pipeline,并且传入了当前的channel对象

protected DefaultChannelPipeline(Channel 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;
    }

从这个构造方法中我们就可以看出,实际上,pipeline对传入的信息进行处理是通过里面保存的节点,这些节点有组成了一个双向链表进行链式调用。先来看一些尾节点是如何创建的:

tail = new TailContext(this);

尾节点是直接通过构造方法创建的并且传入当前的pipeline对象:
在这里插入图片描述
发现这个尾节点实现了ChannelInboundHandler接口,应该是处理入方向的事件,我们来看一下这个接口中有什么方法:

/**
     * The {@link Channel} of the {@link ChannelHandlerContext} was registered with its {@link EventLoop}
     */
    void channelRegistered(ChannelHandlerContext ctx) throws Exception;

    /**
     * The {@link Channel} of the {@link ChannelHandlerContext} was unregistered from its {@link EventLoop}
     */
    void channelUnregistered(ChannelHandlerContext ctx) throws Exception;

    /**
     * The {@link Channel} of the {@link ChannelHandlerContext} is now active
     */
    void channelActive(ChannelHandlerContext ctx) throws Exception;

    /**
     * The {@link Channel} of the {@link ChannelHandlerContext} was registered is now inactive and reached its
     * end of lifetime.
     */
    void channelInactive(ChannelHandlerContext ctx) throws Exception;

    /**
     * Invoked when the current {@link Channel} has read a message from the peer.
     */
    void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception;

    /**
     * Invoked when the last message read by the current read operation has been consumed by
     * {@link #channelRead(ChannelHandlerContext, Object)}.  If {@link ChannelOption#AUTO_READ} is off, no further
     * attempt to read an inbound data from the current {@link Channel} will be made until
     * {@link ChannelHandlerContext#read()} is called.
     */
    void channelReadComplete(ChannelHandlerContext ctx) throws Exception;

    /**
     * Gets called if an user event was triggered.
     */
    void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception;

    /**
     * Gets called once the writable state of a {@link Channel} changed. You can check the state with
     * {@link Channel#isWritable()}.
     */
    void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception;

    /**
     * Gets called if a {@link Throwable} was thrown.
     */
    @Override
    @SuppressWarnings("deprecation")
    void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;

都是些读事件,注册事件,激活事件的处理。下面我们看一下它的构造方法:

 AbstractChannelHandlerContext(DefaultChannelPipeline pipeline, EventExecutor executor, String name,
                                  boolean inbound, boolean outbound) {
        this.name = ObjectUtil.checkNotNull(name, "name");
        this.pipeline = pipeline;
        this.executor = executor;
        this.inbound = inbound;
        this.outbound = outbound;
        // Its ordered if its driven by the EventLoop or the given Executor is an instanceof OrderedEventExecutor.
        ordered = executor == null || executor instanceof OrderedEventExecutor;
    }

保存了我们传入的参数,尤其要注意,pipeline是通过当前节点inbound和outbound 是true还是false选择合适的节点的。
在这里插入图片描述
需要注意的是头节点是同时继承了ChannelInboundHandler和ChannelOutboundHandler接口,但是记录的自己是一个出站节点。
接下来我们看一下pipeline是如何添加一个节点的

public final ChannelPipeline addLast(ChannelHandler... handlers) {
        return addLast(null, handlers);
    }

将我们传入的handler数组当作参数去调用另外一个方法:

 public final ChannelPipeline addLast(EventExecutorGroup executor, ChannelHandler... handlers) {
 		//进行非空判断
        if (handlers == null) {
            throw new NullPointerException("handlers");
        }
		//通过循环一个一个的将这些handler添加到链表的尾部
        for (ChannelHandler h: handlers) {
            if (h == null) {
                break;
            }
            addLast(executor, null, h);
        }

        return this;
    }
public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
        final AbstractChannelHandlerContext newCtx;
        synchronized (this) {
            checkMultiplicity(handler);
			//封装成一个新的节点
            newCtx = newContext(group, filterName(name, handler), handler);
			//最终封装好的新节点添加到链表上
            addLast0(newCtx);

            // 如果添加失败了,那么就会把这个节点的封装成一个任务放到队列里面稍后执行
            if (!registered) {
                newCtx.setAddPending();
                callHandlerCallbackLater(newCtx, true);
                return this;
            }

            EventExecutor executor = newCtx.executor();
            if (!executor.inEventLoop()) {
                newCtx.setAddPending();
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        callHandlerAdded0(newCtx);
                    }
                });
                return this;
            }
        }
        //添加完成之后调用回调方法
        callHandlerAdded0(newCtx);
        return this;
    }

在这个方法中做了两件事:
1、将handler封装成一个context节点并最终调用添加方法
2、添加完成之后调用回调方法
接下来我们一个一个的去看这是怎么实现的:

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

这就是双向链表添加一个新节点的操作,没什么好说的

private void callHandlerAdded0(final AbstractChannelHandlerContext ctx) {
        try {
        	//添加完成后的回调方法
            ctx.handler().handlerAdded(ctx);
            ctx.setAddComplete();
        } catch (Throwable t) {
            boolean removed = false;
            try {
                remove0(ctx);
                try {
                    ctx.handler().handlerRemoved(ctx);
                } finally {
                    ctx.setRemoved();
                }
                removed = true;
            } catch (Throwable t2) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Failed to remove a handler: " + ctx.name(), t2);
                }
            }

            if (removed) {
                fireExceptionCaught(new ChannelPipelineException(
                        ctx.handler().getClass().getName() +
                        ".handlerAdded() has thrown an exception; removed.", t));
            } else {
                fireExceptionCaught(new ChannelPipelineException(
                        ctx.handler().getClass().getName() +
                        ".handlerAdded() has thrown an exception; also failed to remove.", t));
            }
        }
    }

这个回调方法是非常重要的,ctx.handler().handlerAdded(ctx),这个方法中调用了用户自定义实现的方法,就是下面这几行代码:

.childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) {
                            ch.pipeline().addLast(new OutBoundHandlerA());
                            ch.pipeline().addLast(new OutBoundHandlerC());
                            ch.pipeline().addLast(new OutBoundHandlerB());
                        }
                    });

这是用户通过添加一个childHandler而在里面的自定义方法中添加多个handler,而这几个handler的添加就是通过上面的回调函数放上去的,添加完成之后就会将这个childHandler删除掉。
下面我们就来看一下pipeline是如何删除一个节点的:

public final ChannelHandlerContext context(ChannelHandler handler) {
        if (handler == null) {
            throw new NullPointerException("handler");
        }

        AbstractChannelHandlerContext ctx = head.next;
        for (;;) {

            if (ctx == null) {
                return null;
            }

            if (ctx.handler() == handler) {
                return ctx;
            }

            ctx = ctx.next;
        }
    }

首先需要在链表上查找指定的handler对应的ctx,找到之后返回ctx,没有就返回空:

private AbstractChannelHandlerContext getContextOrDie(ChannelHandler handler) {
        AbstractChannelHandlerContext ctx = (AbstractChannelHandlerContext) context(handler);
        if (ctx == null) {
            throw new NoSuchElementException(handler.getClass().getName());
        } else {
            return ctx;
        }
    }

接着会判断是否存在handler,如果存在那么直接返回,不存在抛出异常

public final ChannelPipeline remove(ChannelHandler handler) {
        remove(getContextOrDie(handler));
        return this;
    }

然后就会继续调用remove方法,参数则是handler对应的context

private AbstractChannelHandlerContext remove(final AbstractChannelHandlerContext ctx) {
        assert ctx != head && ctx != tail;

        synchronized (this) {
            remove0(ctx);
            if (!registered) {
                callHandlerCallbackLater(ctx, false);
                return ctx;
            }

            EventExecutor executor = ctx.executor();
            if (!executor.inEventLoop()) {
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        callHandlerRemoved0(ctx);
                    }
                });
                return ctx;
            }
        }
        callHandlerRemoved0(ctx);
        return ctx;
    }

这段代码就和add方法是一样的了,先调用最终的remove方法,通过链表的操作删除节点,然后调用回调方法,我们就不进去看了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值