java netty之DefaultChannelPipeline

前面分析过ChannelPipeline的定义,以及它的集成体系,这篇文章深入一些,分写一个它的实现类DefaultChannelPipeline,它直接实现了ChannelPipeline接口。。。

我们首先来看它的一些重要的属性:

    final Channel channel; //当前pipeline所属的channel

    //head和tail都是handler上下文,但是不同的是head它包含的是一个outboundhandler,同时也是operationhanderl
    //而tail包含的是一个inboundhandler,同时也是一个stathandler
    final DefaultChannelHandlerContext head;
    final DefaultChannelHandlerContext tail;

    private final Map name2ctx =
        new HashMap(4);   //用于保存所有的handlercontext与name之间的关系
其实这些属性基本上都能知道是干嘛的,首先channel保存的是当前pipeline所依附的channel,

然后这里的head与tail都是handlercontext,从名字就会知道他们会用来构成一个链,具体的待会从构造函数中就能知道它们用来干嘛了。。。

然后还有一个map用来存储名字与handler之间的关系。。。。

接下来我们来看它的构造函数:

    public DefaultChannelPipeline(Channel channel) {
        if (channel == null) {
            throw new NullPointerException("channel");
        }
        this.channel = channel;  //为所属的channel赋值

        TailHandler tailHandler = new TailHandler();  //构造尾handler,它是一个inboundhandler,同时当然也是stathandler了
        tail = new DefaultChannelHandlerContext(this, generateName(tailHandler), tailHandler);

        HeadHandler headHandler;   
        //接下来开始构造headhandler,它是一个outboundhandler,也就是一个operationhandler
        switch (channel.metadata().bufferType()) {
        case BYTE:
        	//operationhandler需要用channel对象的unsafe对象来构造
            headHandler = new ByteHeadHandler(channel.unsafe());
            break;
        case MESSAGE:
            headHandler = new MessageHeadHandler(channel.unsafe());
            break;
        default:
            throw new Error("unknown buffer type: " + channel.metadata().bufferType());
        }

        head = new DefaultChannelHandlerContext(this, generateName(headHandler), headHandler);
//将他们构成链表
        head.next = tail;
        tail.prev = head;
    }
还是相对比较简单,首先是为channel属性赋值,接着初始化head与tail属性,

这里需要预先预习一下两种handler,inboundhandler与outboundhandler,同时inboundhandler实现了stathandler接口,outboundhandler实现了operationhandler接口,说白了inboundhandler用来处理读进来的数据,而outboundhandler用来具体对外的数据操作。。。

这里head将最终包含一个outboundhandler,而tail将最终包含一个inboundhandler。。。

而且最终handler的调用方式是:

(1)对于已经读取的数据需要处理,将会从head开始向下遍历,找到第一个inboundhandler,然后将数据保存到它的buffer,然后由它来处理。。。

(2)对于需要进行对外的操作,那么将会从tail开始,向上遍历,找到第一个outboundhandler,然后由它来处理。。。


我们首先来看内部类TailHandler的实现:

  // A special catch-all handler that handles both bytes and messages.
    static final class TailHandler implements ChannelInboundHandler {

        final ByteBuf byteSink = Unpooled.buffer(0);
        final MessageBuf msgSink = Unpooled.messageBuffer(0);

        @Override
        public void channelRegistered(ChannelHandlerContext ctx) throws Exception { }

        @Override
        public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { }

        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception { }

        @Override
        public void channelInactive(ChannelHandlerContext ctx) throws Exception { }

        @Override
        public void channelReadSuspended(ChannelHandlerContext ctx) throws Exception { }

        @Override
        public void handlerAdded(ChannelHandlerContext ctx) throws Exception { }

        @Override
        public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { }

        @Override
        public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            logger.warn(
                    "An exceptionCaught() event was fired, and it reached at the tail of the pipeline. " +
                            "It usually means the last handler in the pipeline did not handle the exception.", cause);
        }

        @Override
        public Buf newInboundBuffer(ChannelHandlerContext ctx) throws Exception {
            throw new Error();
        }

        @Override
        //数据居然要交到tailhandler来处理了,其实很简单,就是直接丢弃这些数据
        public void inboundBufferUpdated(ChannelHandlerContext ctx) throws Exception {
            int byteSinkSize = byteSink.readableBytes();
            if (byteSinkSize != 0) {
                byteSink.clear();
                logger.warn(
                        "Discarded {} inbound byte(s) that reached at the tail of the pipeline. " +
                        "Please check your pipeline configuration.", byteSinkSize);
            }

            int msgSinkSize = msgSink.size();
            if (msgSinkSize != 0) {
                MessageBuf in = msgSink;
                for (;;) {
                    Object m = in.poll();
                    if (m == null) {
                        break;
                    }
                    BufUtil.release(m);
                    logger.debug(
                            "Discarded inbound message {} that reached at the tail of the pipeline. " +
                                    "Please check your pipeline configuration.", m);
                }
                logger.warn(
                        "Discarded {} inbound message(s) that reached at the tail of the pipeline. " +
                        "Please check your pipeline configuration.", msgSinkSize);
            }
        }
    }
它直接继承自inboundhandler,因此实现了所有inboundhandler的方法,其实也就实现了inboundBufferUpdated方法,其余的方法都是空的。。。 
  

这是默认的tail包含的handler,因此也就是最后一个inboundhandler,如果最终不得不由这个handler来处理读取进来的数据,那么就是说明在整个pipeline上面根本就没有用户定义的inboundhandler来处理读进来的数据,这个时候进行的操作就是直接将这些读取的数据抛弃掉就好了。。。。

接下来来看内部类HeadHandler的定义:

    abstract static class HeadHandler implements ChannelOutboundHandler {

        protected final Unsafe unsafe;
        ByteBuf byteSink;
        MessageBuf msgSink;
        boolean initialized;

        //构造函数,这个时候的unsafe就是channel的unsafe对象
        protected HeadHandler(Unsafe unsafe) {
            this.unsafe = unsafe;
        }

        void init(ChannelHandlerContext ctx) {
            assert !initialized;
            switch (ctx.channel().metadata().bufferType()) {
            case BYTE:
                byteSink = ctx.alloc().ioBuffer();
                msgSink = Unpooled.messageBuffer(0);
                break;
            case MESSAGE:
                byteSink = Unpooled.buffer(0);
                msgSink = Unpooled.messageBuffer();
                break;
            default:
                throw new Error();
            }
        }

        @Override
        public final void handlerAdded(ChannelHandlerContext ctx) throws Exception {
            // NOOP
        }

        @Override
        public final void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
            // NOOP
        }

        @Override
        public final void bind(
                ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise)
                throws Exception {
            unsafe.bind(localAddress, promise);
        }

        @Override
        public final void connect(
                ChannelHandlerContext ctx,
                SocketAddress remoteAddress, SocketAddress localAddress,
                ChannelPromise promise) throws Exception {
            unsafe.connect(remoteAddress, localAddress, promise);
        }

        @Override
        public final void disconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
            unsafe.disconnect(promise);
        }

        @Override
        public final void close(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
            unsafe.close(promise);
        }

        @Override
        public final void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
            unsafe.deregister(promise);
        }

        @Override
        public final void read(ChannelHandlerContext ctx) {
            unsafe.beginRead();
        }

        @Override
        public final void sendFile(
                ChannelHandlerContext ctx, FileRegion region, ChannelPromise promise) throws Exception {
            unsafe.sendFile(region, promise);
        }

        @Override
        public final Buf newOutboundBuffer(ChannelHandlerContext ctx) throws Exception {
            throw new Error();
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            ctx.fireExceptionCaught(cause);
        }
    }它是一个抽象类,因为需要分为两种,基于byte类型的以及基于message类型的。。。 
  

另外我们可以看到一个unsafe对象,其实这个就是当前所属的channel的unsafe对象,对于实际的操作,例如connect,bind等,其实都是基于这个对象来实现的。。。。

对于它的子类,ByteHeadHandler和MessageHeadHandler,他们具体实现了flush方法,用于发送数据,其实数白了最后总还是用unsafe的flush方法来实现的...

看到这里,也能看出,对于outboundhandler不一定需要用户自定义也可以,因为默认的head将会按照channel的unsafe对象将他们发送出去,但是inboundhandler就必须自己定义了。。。。


这里我们来具体分析一个方法:fireInboundBufferUpdated,它是在事件循环中,通过channel的unsafe对象读取到数据后,将会调用的方法,表示已经有数据已经读取了,然后触发inboundhandler来处理这些数据,在DefaultChannelPipeline中这个方法的实现很简单:

    //当从nio的channel中读取了数据之后会调用这个方法,最终会激活handler链上的第一个inboundhandler的inboundBufferUpdated方法来处理这些数据
    public ChannelPipeline fireInboundBufferUpdated() {
        head.fireInboundBufferUpdated();
        return this;
    }
说白了就是调用headhandler的context的fireInboundBufferUpdated方法(headhandler是一个outboundhandler),那么我们接下来来看看DefaultChannelHandlerContext中该方法的定义吧:
    @Override
    //当已经有数据从nio的channel中读取进来的时候,会调用该方法,用于处理读取进来的数据
    public ChannelHandlerContext fireInboundBufferUpdated() {
        EventExecutor executor = executor();  //用于获取执行代码的executor,其实一般情况下就是当前channel所属的eventLoop
        if (executor.inEventLoop()) {      //如果executor就是当前的eventLoop,那么就直接执行好了否则的话需要向executor提交任务
            fireInboundBufferUpdated0(findContextInbound());
        } else {
            Runnable task = fireInboundBufferUpdated0Task;
            if (task == null) {
                fireInboundBufferUpdated0Task = task = new Runnable() {
                    @Override
                    public void run() {
                        fireInboundBufferUpdated0(findContextInbound());
                    }
                };
            }
            executor.execute(task);
        }
        return this;
    }
实现首先是判断当前的executor的线程是否就是当前的执行线程,其实一般情况下都是的,也就是当前channel所属的eventLoop,除非为当前的handler指定了额外的executor,如果有额外的executor的话,那么就需要通过task的方法来执行了。。。这里在具体的执行之前先调用了findContextInbound方法来找到第一个inboundhandler的context,我们来看看该方法的定义吧:
    }
//headhandler的context会调用该方法,用于向下寻找,找到第一个inboundhandler的context
    private DefaultChannelHandlerContext findContextInbound() {
        DefaultChannelHandlerContext ctx = this;
        do {
            ctx = ctx.next;
        } while (!(ctx.handler() instanceof ChannelStateHandler));
        return ctx;
    }
这里就能看出,对于读取进来的数据,handler是从head到tail执行的顺序了吧、、、

好了接下来来看fireInboundBufferUpdated0方法:

    private void fireInboundBufferUpdated0(final DefaultChannelHandlerContext next) {
    	//handler的buffer之间的联系
        feedNextInBridge();
        // This comparison is safe because this method is always executed from the executor.
        if (next.executor == executor) {   //有可能找到的第一个inboundhandler的executor不是当前这个executor,不过一般还是当前channel注册到的eventLoop
            next.invokeInboundBufferUpdated();   //这里说白了就是调用具体的inboundhandler的inboundBufferUpdated方法
        } else {
            Runnable task = next.invokeInboundBufferUpdatedTask;
            if (task == null) {
                next.invokeInboundBufferUpdatedTask = task = new Runnable() {
                    @Override
                    public void run() {
                        next.invokeInboundBufferUpdated();
                    }
                };
            }
            next.executor().execute(task);
        }
    }
先刷新了bridge,接着还是判断了executor,最后在调用invokeInboundBufferUpdated方法,来看它的定义:
    //具体调用inboundhandler的inboundBufferUpdated方法来处理读进来的数据
    private void invokeInboundBufferUpdated() {
        if (isInboundFreed()) {
            return;
        }

        ChannelStateHandler handler = (ChannelStateHandler) handler();
        if (handler instanceof ChannelInboundHandler) {
            for (;;) {
                try {
                    boolean flushedAll = flushInboundBridge();
                    handler.inboundBufferUpdated(this);   //调用inboundBufferUpdated函数来处理读进来的数据
                    if (flushedAll) {
                        break;
                    }
                } catch (Throwable t) {
                    notifyHandlerException(t);
                    break;
                } finally {
                    if (handler instanceof ChannelInboundByteHandler && !isInboundFreed()) {
                        try {
                            ((ChannelInboundByteHandler) handler).discardInboundReadBytes(this);
                        } catch (Throwable t) {
                            notifyHandlerException(t);
                        }
                    }
                    freeHandlerBuffersAfterRemoval();
                }
            }
        } else {
            try {
                handler.inboundBufferUpdated(this);
            } catch (Throwable t) {
                notifyHandlerException(t);
            }
        }
    }
这里调用了inboundhandler的inboundBufferUpdated方法,这个用过netty的就应该很清楚了吧。。。


好了,对于真个数据进来的处理流程就差不了。。。好像也不是说的太细,而且有一些细节我也没有搞的太清楚,例如bridge,不过以后补上吧。。。

你可能感兴趣的:(netty)