Netty源码解析(七) —— Pipeline的工作机制

Pipeline是一个由HandlerContext节点构成的双向环形链表,结构如下图,最前面是HeadContext,末尾是TailContext中间是用户自定义的HandlerContext节点

这里写图片描述
先来看pipLine的构造参数

    /**
     * channelPipLine的默认构造方法
     * @param channel
     */
    protected DefaultChannelPipeline(Channel channel) {
        this.channel = ObjectUtil.checkNotNull(channel, "channel");
        succeededFuture = new SucceededChannelFuture(channel, null);
        voidPromise =  new VoidChannelPromise(channel, true);

        //创建TailContext
        tail = new TailContext(this);
        //创建HeadContext
        head = new HeadContext(this);

        head.next = tail;
        tail.prev = head;
    }

可以看到pipline默认创建一个head和tail并且组成一个双向链表,而pipline的创建需要一个channel作为参数,实际上pipline是在channel里面创建的(即一个channel对应一个pipline)
pipline的添加节点方法

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

最终调用到

    @Override
    public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
        final AbstractChannelHandlerContext newCtx;
        synchronized (this) {
            //检查handler是否重复添加
            checkMultiplicity(handler);

            //创建pipLine节点
            newCtx = newContext(group, filterName(name, handler), handler);
            //添加节点操作
            addLast0(newCtx);

            if (!registered) {
                newCtx.setAddPending();
                callHandlerCallbackLater(newCtx, true);
                return this;
            }

            EventExecutor executor = newCtx.executor();
            //判断当前线程是否是NioEventLoop运行线程
            if (!executor.inEventLoop()) {
                newCtx.setAddPending();
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        //调用hander的add方法
                        callHandlerAdded0(newCtx);
                    }
                });
                return this;
            }
        }
        callHandlerAdded0(newCtx);
        return this;
    }
  1. 检查handler是否重复添加
  2. 创建pipLine节点
  3. 添加节点操作
  4. 调用hander的add方法

io.netty.channel.DefaultChannelPipeline#checkMultiplicity

    private static void checkMultiplicity(ChannelHandler handler) {
        if (handler instanceof ChannelHandlerAdapter) {
            ChannelHandlerAdapter h = (ChannelHandlerAdapter) handler;
            /**
             * 如果handler没有@Sharable注解修饰
             * 并且被添加过了,抛出异常
             */
            if (!h.isSharable() && h.added) {
                throw new ChannelPipelineException(
                        h.getClass().getName() +
                        " is not a @Sharable handler, so can't be added or removed multiple times.");
            }
            h.added = true;
        }
    }

对于一个adapter如果我们想要把它添加到多个pipline中去,可以加一个@Sharable注解修饰,负责会抛异常
io.netty.channel.DefaultChannelPipeline#newContext

    private AbstractChannelHandlerContext newContext(EventExecutorGroup group, String name, ChannelHandler handler) {
        return new DefaultChannelHandlerContext(this, childExecutor(group), name, handler);
    }
    private String filterName(String name, ChannelHandler handler) {
        if (name == null) {
            //根据handler生成一个对应的name
            return generateName(handler);
        }
        //检查name是否重复
        checkDuplicateName(name);
        return name;
    }

io.netty.channel.DefaultChannelPipeline#checkDuplicateName

    private void checkDuplicateName(String name) {
        if (context0(name) != null) {
            throw new IllegalArgumentException("Duplicate handler name: " + name);
        }
    }

    /**
     * 遍历head->....->tail节点name  看是否name重复
     * @param name
     * @return
     */
    private AbstractChannelHandlerContext context0(String name) {
        AbstractChannelHandlerContext context = head.next;
        while (context != tail) {
            if (context.name().equals(name)) {
                return context;
            }
            context = context.next;
        }
        return null;
    }

io.netty.channel.DefaultChannelPipeline#addLast0

    //把创建的新节点添加到pipLine尾部
    private void addLast0(AbstractChannelHandlerContext newCtx) {
        AbstractChannelHandlerContext prev = tail.prev;
        newCtx.prev = prev;
        newCtx.next = tail;
        prev.next = newCtx;
        tail.prev = newCtx;
    }

基本的链表操作,对链表操作熟悉的同学很容易理解


io.netty.channel.DefaultChannelPipeline#callHandlerAdded0

   private void callHandlerAdded0(final AbstractChannelHandlerContext ctx) {
        try {
            ctx.setAddComplete();
            //调用handler的handlerAdded方法
            /**
             * p.addLast(new ChannelInitializer<Channel>() {
             * 会调用ChannelInitializer的handlerAdded(ctx)方法
             */
            ctx.handler().handlerAdded(ctx);
        } catch (Throwable t) {
            ......
    }

添加完成之后修改节点的状态,并且调用对应handler的handlerAdded方法,用户可以在这个方法里面进行操作,或者把事件往下个节点传递


再看DefaultChannelHandlerContext节点


    private final ChannelHandler handler;

    DefaultChannelHandlerContext(
            DefaultChannelPipeline pipeline, EventExecutor executor, String name, ChannelHandler handler) {
        super(pipeline, executor, name, isInbound(handler), isOutbound(handler));
        if (handler == null) {
            throw new NullPointerException("handler");
        }
        this.handler = handler;
    }

就是一个保存了handler的数据结构,连接上一个和下一个节点


那么我们来思考一个问题客户端channel在连接到服务端channel之后是是怎么构建pipline,并且给pipline装配handlerContext节点
还记得前几篇我们说过,服务端channel在accept事件到来之后,

            /**
             * 读事件和 accept事件都会经过这里,但是拿到的unsafe对象不同  所以后续执行的read操作也不一样
             * NioServerChannel进行accept操作
             * NioChannel进行read操作
             */
            if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
                unsafe.read();
            }

接着调用io.netty.channel.nio.AbstractNioMessageChannel.NioMessageUnsafe#read

        @Override
        public void read() {
            assert eventLoop().inEventLoop();
            final ChannelConfig config = config();
            //拿到channel处理的pipline
            final ChannelPipeline pipeline = pipeline();
            final RecvByteBufAllocator.Handle allocHandle = unsafe().recvBufAllocHandle();
            allocHandle.reset(config);

            boolean closed = false;
            Throwable exception = null;
            try {
                try {
                    do {
                        //readBuf是一个集合  来保存accept出的channel
                        //具体read操作
                        int localRead = doReadMessages(readBuf);
                        if (localRead == 0) {
                            break;
                        }
                        if (localRead < 0) {
                            closed = true;
                            break;
                        }

                        allocHandle.incMessagesRead(localRead);
                    } while (allocHandle.continueReading());
                } catch (Throwable t) {
                    exception = t;
                }

                int size = readBuf.size();
                for (int i = 0; i < size; i ++) {
                    readPending = false;
                    //调用pipline的read方法通知事件
                    pipeline.fireChannelRead(readBuf.get(i));
                }
                //清除readBuf集合
                readBuf.clear();
                allocHandle.readComplete();
                pipeline.fireChannelReadComplete();

                if (exception != null) {
                    closed = closeOnReadError(exception);

                    pipeline.fireExceptionCaught(exception);
                }

                if (closed) {
                    inputShutdown = true;
                    if (isOpen()) {
                        close(voidPromise());
                    }
                }
            } finally {
                .....
                if (!readPending && !config.isAutoRead()) {
                    removeReadOp();
                }
            }
        }
    }

调用pipeline.fireChannelRead(readBuf.get(i));来通知事件,最后从headcontext走到服务端启动的时候的添加的一个handler#ServerBootstrapAcceptor

        @Override
        @SuppressWarnings("unchecked")
        public void channelRead(ChannelHandlerContext ctx, Object msg) {
            //msg 新连接进来会传播事件 传递进来的channel对象
            final Channel child = (Channel) msg;
            //取出来新连接的pipLine 把Server端配置的handler添加进去
            child.pipeline().addLast(childHandler);
            setChannelOptions(child, childOptions, logger);

            for (Entry<AttributeKey<?>, Object> e: childAttrs) {
                child.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());
            }
            try {
                //childGroup其实就是worker NioEventLoopGroup,去注册客户端的channel对象
                childGroup.register(child).addListener(new ChannelFutureListener() {
                    @Override
                    public void operationComplete(ChannelFuture future) throws Exception {
                        if (!future.isSuccess()) {
                            forceClose(child, future.cause());
                        }
                    }
                });
            } catch (Throwable t) {
                forceClose(child, t);
            }
        }

在这里会完成客户端channel中pipline添加处理器节点,而这个节点正是服务启动时设置给ServerBootstrap的

             .childHandler(new ChannelInitializer<SocketChannel>() {
                 @Override
                 public void initChannel(SocketChannel ch) throws Exception {
                     ChannelPipeline p = ch.pipeline();
                     if (sslCtx != null) {
                         p.addLast(sslCtx.newHandler(ch.alloc()));
                     }
                     //p.addLast(new LoggingHandler(LogLevel.INFO));
                     p.addLast(serverHandler);
                 }
             });

那么我们知道每个客户端到来都会把这个handler添加到pipline中去,在pipline中有个重复添加的校验代码,ChannelInitializer是如何通过校验的呢?答案肯定是@Sharable

@Sharable
public abstract class ChannelInitializer<C extends Channel> extends ChannelInboundHandlerAdapter {

另一个就是pipline是什么时候创建的,还有服务端accept的客户端是java原生的channel,在哪完成的包装成netty自己的NioSocketChannel
io.netty.channel.nio.AbstractNioMessageChannel#doReadMessages

    @Override
    protected int doReadMessages(List<Object> buf) throws Exception {
        //拿到新连接的channel
        SocketChannel ch = SocketUtils.accept(javaChannel());

        try {
            if (ch != null) {
                //添加到集合中去
                buf.add(new NioSocketChannel(this, ch));
                return 1;
            }

new NioSocketChannel(this, ch)
就是在这一步完成的原生channel到netty NioSocketChannel的包装
再看NioSocketChannel构造方法

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

看到这里是不是很清晰了,netty的设计思想层层递进,级级抽取

猜你喜欢

转载自blog.csdn.net/u011702633/article/details/82019991