Netty源码分析-Pipeline

Netty版本4.1.22
pipeline可以看作是一个拦截流经Channel的入站和出站事件的ChannelHandler实例链。
在这里插入图片描述
前面分析的NioServerSocketChannelNioSocketChannel在创建时都会创建自己的pipeline,在AbstractChannel中。
《Netty权威指南》里的一张图:
在这里插入图片描述

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

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

来看看DefaultChannelPipeline

    final AbstractChannelHandlerContext head;
    final AbstractChannelHandlerContext tail;
    
    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;
    }

保存chnnel引用,创建了两个AbstractChannelHandlerContext 对象,关于headtail

final class HeadContext extends AbstractChannelHandlerContext
            implements ChannelOutboundHandler, ChannelInboundHandler {

final class TailContext extends AbstractChannelHandlerContext implements 
			ChannelInboundHandler {

head既是inbound也是outboundtailinbound
此时整个pipeline是这样。
图片来自博客:简书闪电侠pipeline中的每个节点是一个ChannelHandlerContext对象。ChannelHandlerContext代表ChannelHandler和channelPipeline之间的关联,每当有ChannelHandler添加到ChannelPipeline中时,都会创建ChannelHandlerContext。其主要功能是管理它所关联的ChannelHandler与同在一个ChannelPipeline中的其它ChannelHandler之间的交互。

pipeline添加节点

bootstrap.group(bossGroup, workerGroup)
	.channel(NioServerSocketChannel.class)
 	.childHandler(new ChannelInitializer<SocketChannel>() {
 			@Override
			protected void initChannel(SocketChannel socketChannel) throws Exception {
				socketChannel.pipeline()
					.addLast("IdleStateHandler", new IdleStateHandler(10, 0, 0))
				    .addLast("LengthFieldPrepender", new LengthFieldPrepender(4, 0))
					.addLast("RpcEncoder", new RpcEncoder())
 					.addLast("LengthFieldBasedFrameDecoder", 
 							new LengthFieldBasedFrameDecoder(1024 * 1024, 0,4,0,4))
 				    .addLast("RpcDecoder", new RpcDecoder())
  				    .addLast("RpcServerHandler", new RpcServerHandler(handlerMap));
 		    }
	 })

来跟踪addLast方法

DefaultChannelPipeline:

    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); // 检测handler是否已添加
			// 创建节点
            newCtx = newContext(group, filterName(name, handler), handler);
			// 添加节点
            addLast0(newCtx);

            // registered 为false表明channel并没有注册到它的pipeline上,
            // 那么就将newCtx封装成一个任务加到任务链表,当channel注册完成后
            // 再触发callHandlerAdded0,他会触发handler的handlerAdded
            if (!registered) {
                newCtx.setAddPending();
                callHandlerCallbackLater(newCtx, true);
                return this;
            }

// 若你调用addLast时传入group,则上面newContext方法在构建headlerContext
// 的时候,会从group种next一个NioEventLoop赋给
// AbstractChannelHandlerContext.executor字段,
// 作为一个child executor,即子线程
// 有什么用处?比如这里,若存在child executor则将callHandlerAdded0交给
// 该子线程处理。若不存在,则由当前NioEventLoop的线程来处理,
// 那么当前线程是哪个线程?
            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;
    }

对pipeline中context节点操作由synchronized保护,即对handler链的更改要确保安全性。
newCtx.executor()定位到AbstractChannelHandlerContext

    public EventExecutor executor() {
        if (executor == null) {
            return channel().eventLoop();
        } else {
            return executor;
        }
    }

    public Channel channel() {
        return pipeline.channel();
    }

这里addLast时没传入group,则AbstractChannelHandlerContext.executor为null,返回与pipeline关联的channnel的EventLoop,比如顺着上面的例子(childHandler的addLast)则这里返回的就是NioSocketChannel初始化时创建的NioEventLoop,执行这些代码的线程也是该eventLoop的线程,之前连接一篇中分析过,NioServerSocketChannel的线程从连接事件到来一路执行到其pipeline里ServerBootstrapAcceptorchannelRead,再该方法里childGroup.register(child),跟踪注册逻辑到AbstractUnsafe的register,在这里创建启动NioSocketChannel所属NioEventLoop的线程(前提是该NioEventLoop没有线程),register0就交给它来执行,为什么说执行上面addLast的是该线程?因为ChannelInitializer的initChannel在register0里被调用,详细分析在连接一篇中。

插一句,源码分析到这里,究竟是哪个线程在执行,理清它有助于对过程的理解,总之一个NioEventLoop只有一个线程,而channel一旦被注册到某个NioEventLoop上就不会更改,对于每个channel都是单线程操作,落在代码层面要做的就是在一些要保护的方法执行前判断eventLoop.inEventLoop(),true就直接执行,false就封装成任务放入队列,留线程启动后再执行。那么哪些方法要保护?线程又在何处启动?由之前的分析来看无论是NioServerSocketChannel还是NioSocketChannel,它们所属的NioEventLoop的线程都是在register方法里被启动的,因为register0方法是需要保护的方法。

1,checkMultiplicity检测该handler是否已添加

    private static void checkMultiplicity(ChannelHandler handler) {
        if (handler instanceof ChannelHandlerAdapter) {
            ChannelHandlerAdapter h = (ChannelHandlerAdapter) handler;
            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;
        }
    }

在这里插入图片描述
如果该handler是非共享的且已经添加过(hanler的added标识一个handler是否已添加)则抛异常。否则h.added = true;标识该handler为已添加。

关于共享handler

@Sharable
public class BusinessHandler {
    
}

isSharable() 检测的就是该注解

    public boolean isSharable() {
        Class<?> clazz = getClass();
        Map<Class<?>, Boolean> cache = InternalThreadLocalMap.get().handlerSharableCache();
        Boolean sharable = cache.get(clazz);
        if (sharable == null) {
            sharable = clazz.isAnnotationPresent(Sharable.class);
            cache.put(clazz, sharable);
        }
        return sharable;
    }

2,newContext创建节点

newCtx = newContext(group, filterName(name, handler), handler);

filterName给handler创建一个唯一性的名字。

    private AbstractChannelHandlerContext newContext(EventExecutorGroup group, String name, ChannelHandler handler) {
        return new DefaultChannelHandlerContext(this, childExecutor(group), name, handler);
    }

先来看看childExecutor(group),group为null则返回null

    private EventExecutor childExecutor(EventExecutorGroup group) {
        if (group == null) {
            return null;
        }
        // 检查SINGLE_EVENTEXECUTOR_PER_GROUP属性,默认为true,代表
        // 整个pipeline由一个线程来执行
        Boolean pinEventExecutor = channel.config().getOption(ChannelOption.SINGLE_EVENTEXECUTOR_PER_GROUP);
        if (pinEventExecutor != null && !pinEventExecutor) {
            return group.next();  // 若为false,则从group中选择一个线程来执行,不推荐
        }
// 下面的操作就是从group中选择一个NioEventLoop,再将group与该eventLoop关联并存储
// 下次同一group用同一eventLoop
        Map<EventExecutorGroup, EventExecutor> childExecutors = this.childExecutors;
        if (childExecutors == null) {
            // Use size of 4 as most people only use one extra EventExecutor.
            childExecutors = this.childExecutors = new IdentityHashMap<EventExecutorGroup, EventExecutor>(4);
        }
        // Pin one of the child executors once and remember it so that the same child executor
        // is used to fire events for the same channel.
        EventExecutor childExecutor = childExecutors.get(group);
        if (childExecutor == null) {
            childExecutor = group.next();
            childExecutors.put(group, childExecutor);
        }
        return childExecutor;
    }

SINGLE_EVENTEXECUTOR_PER_GROUP
Netty参数,单线程执行ChannelPipeline中的事件,默认值为True。该值控制执行ChannelPipeline中执行ChannelHandler的线程。如果为True,整个pipeline由一个线程执行,这样不需要进行线程切换以及线程同步,是Netty4的推荐做法;如果为False,ChannelHandler中的处理过程会由Group中的不同线程执行。

继续,DefaultChannelHandlerContext

    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;
    }

    private static boolean isInbound(ChannelHandler handler) {
        return handler instanceof ChannelInboundHandler;
    }

    private static boolean isOutbound(ChannelHandler handler) {
        return handler instanceof ChannelOutboundHandler;
    }

保存handler引用

    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;
    }

3,addLast0(newCtx)添加节点

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

典型的双向链表插入过程,插入到tail节点之前。

4, callHandlerAdded0回掉handler的handlerAdded()
之前连接一篇很长一大篇来分析ChannelInitializerinitChannel什么时候被调用,就是在这里 callHandlerAdded0

    private void callHandlerAdded0(final AbstractChannelHandlerContext ctx) {
        try {
            // We must call setAddComplete before calling handlerAdded. 
            // Otherwise if the handlerAdded method generates
            // any pipeline events ctx.handler() will miss them because
            // the state will not allow it.
            ctx.setAddComplete();
            ctx.handler().handlerAdded(ctx);

先调用setAddComplete

    /**
     * ChannelHandler#handlerAdded(ChannelHandlerContext) is about to be called.
     */
    private static final int ADD_PENDING = 1;
    /**
     * ChannelHandler#handlerAdded(ChannelHandlerContext) was called.
     */
    private static final int ADD_COMPLETE = 2;
    /**
     * ChannelHandler#handlerRemoved(ChannelHandlerContext) was called.
     */
    private static final int REMOVE_COMPLETE = 3;
    /**
     * Neither ChannelHandler#handlerAdded(ChannelHandlerContext)
     * nor ChannelHandler#handlerRemoved(ChannelHandlerContext) was called.
     */
    private static final int INIT = 0;
    
	private volatile int handlerState = INIT;
	
    private static final AtomicIntegerFieldUpdater<AbstractChannelHandlerContext> 
    		HANDLER_STATE_UPDATER =AtomicIntegerFieldUpdater.newUpdater
    			(AbstractChannelHandlerContext.class, "handlerState");

    final void setAddComplete() {
        for (;;) {
            int oldState = handlerState;
            // Ensure we never update when the handlerState is 
            // REMOVE_COMPLETE already.
            // oldState is usually ADD_PENDING but can also be 
            // REMOVE_COMPLETE when an EventExecutor is used that is not
            // exposing ordering guarantees.
            if (oldState == REMOVE_COMPLETE || 
                HANDLER_STATE_UPDATER.compareAndSet(this, oldState, ADD_COMPLETE)) {
                return;
            }
        }
    }

通常节点状态为ADD_PENDING,CAS更改为ADD_COMPLETE,如果是REMOVE_COMPLETE则不应该更改它。
回到上面,最后会ctx.handler().handlerAdded(ctx);回调该handler的handlerAdded()方法。以ChannelInitializer为例

    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        if (ctx.channel().isRegistered()) { 
            initChannel(ctx);
        }
    }

注释中说运行到里ctx.channel().isRegistered()一定为true,即保证channel已注册,指的是AbstractChannel.registeredtrue,它只在regoster0里被改为true,如何保证callHandlerAdded0的调用满足这一条件,callHandlerAdded0在DefaultChannelPipeline的addFirst,addLast,addBefore,addAfter里被调用,在调用前会检测DefaultChannelPipeline.registered变量值,为false则将该callHandlerAdded0的调用延迟(延迟方法看连接一篇),该变量只在callHandlerAddedForAllHandlers被更改,channel注册在register0里会调用pipeline.invokeHandlerAddedIfNeeded();,如果第一次注册调用callHandlerAddedForAllHandlers,更改DefaultChannelPipeline.registered,调用callHandlerAdded0,这样保证了ctx.channel().isRegistered()一定返回true。
回到ChannelInitializer,它的handlerAdded调用了initChannel

对之前分析中出现的pipeline操作进行分析

  1. register0中出现的invokeHandlerAddedIfNeededfireChannelRegisteredfireChannelActive
  2. 连接阶段出现的fireChannelReadfireChannelReadComplete

invokeHandlerAddedIfNeeded

register0
invokeHandlerAddedIfNeeded:对pipeline中链表的添加删除等改动操作,最后都会调用callHandlerRemoved0,callHandlerAdded0,去改变节点handlerContext的状态,并调用该handler的handlerRemoved,handlerAdded。不过上述有个前提是该channel已注册,所以在未注册情况下,这两个方法的调用被封装起来,等待注册后执行,invokeHandlerAddedIfNeeded就是在注册后触发它们的方法。

fireChannelRegistered

选取一个点分析,服务启动阶段register0,invokeHandlerAddedIfNeeded执行后,NioServerSocketChannel的pipeline变为head->ServerBootstrapAcceptor->tail,假设用户没有设定bootstrap.handler(),所以就只有三个handler。

DefaultChannelPipeline:

    public final ChannelPipeline fireChannelRegistered() {
        AbstractChannelHandlerContext.invokeChannelRegistered(head);
        return this;
    }

传head头节点

    static void invokeChannelRegistered(final AbstractChannelHandlerContext next) {
        EventExecutor executor = next.executor();
        if (executor.inEventLoop()) {
            next.invokeChannelRegistered();
        } else {
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    next.invokeChannelRegistered();
                }
            });
        }
    }

既然是register0方法,那么这里(executor.inEventLoop()返回true

    private void invokeChannelRegistered() {
        if (invokeHandler()) {
            try {
                ((ChannelInboundHandler) handler()).channelRegistered(this);
            } catch (Throwable t) {
                notifyHandlerException(t);
            }
        } else {
            fireChannelRegistered();
        }
    }
    private boolean invokeHandler() {
        // Store in local variable to reduce volatile reads.
        int handlerState = this.handlerState;
        return handlerState == ADD_COMPLETE || (!ordered && handlerState == ADD_PENDING);
    }

该方法检测ChannelHandler#handlerAdded(ChannelHandlerContext)是否已被调用,是返回true。为什么要检测?为了确保加入到pipeline的handler的handlerAdded的执行。

回到invokeChannelRegistered,handler()返回head,来看它的channelRegistered(head),

        public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
            invokeHandlerAddedIfNeeded();
            ctx.fireChannelRegistered();
        }

再次调用了invokeHandlerAddedIfNeeded(),确保handlerAdded的执行,ctx指的是head,ctx.fireChannelRegistered();将channelRegistered事件传递下去

AbstractChannelHandlerContext:

    public ChannelHandlerContext fireChannelRegistered() {
        invokeChannelRegistered(findContextInbound());
        return this;
    }

    private AbstractChannelHandlerContext findContextInbound() {
        AbstractChannelHandlerContext ctx = this;
        do {
            ctx = ctx.next;
        } while (!ctx.inbound);
        return ctx;
    }

当head的channelRegistered执行完,找寻handler链上下一个inbound,调用其channelRegistered,本例子中ServerBootstrapAcceptor extends ChannelInboundHandlerAdapter,ServerBootstrapAcceptor 就是下一个inbound。来看看它的实现,在其父类ChannelInboundHandlerAdapter

ChannelInboundHandlerAdapter:

    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        ctx.fireChannelRegistered();
    }

不做任何反应,直接传递下去,下一个inbound是tail,TailContext extends AbstractChannelHandlerContext implements ChannelInboundHandler

public void channelRegistered(ChannelHandlerContext ctx) throws Exception { }

作为尾节点对channelRegistered事件不做任何处理,事件到此结束。

fireChannelActive

对于服务端启动阶段,fireChannelActive并不会在注册阶段register0方法中被调用,因为NioServerSocketChannel.isActive(该方法有多种实现,由于选的是服务端启动,这里定位到NioServerSocketChannel)只有在成功绑定地址后才会返回true。在服务端启动的绑定阶段,AbstractUnsafe的bind方法里,当doBind实际绑定操作结束后

            if (!wasActive && isActive()) {
                invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        pipeline.fireChannelActive();
                    }
                });
            }

invokeLater就是将其封装策成Runnable加入到taskQueue中。这里是哪个线程在执行,服务端启动的主线程,还是在register方法中启动的reactor线程?回到AbstractBootstrap.doBind0,发现其将之后绑定操作交给了reactor线程来执行。这里的reactor线程指的是NioServerSocketChannel所属的NioEventLoop的线程

所以这里我们分析的阶段定为服务端启动的绑定阶段,AbstractUnsafe的bind方法里,当doBind实际绑定操作结束后,上述代码的执行

    public final ChannelPipeline fireChannelActive() {
        AbstractChannelHandlerContext.invokeChannelActive(head);
        return this;
    }

    static void invokeChannelActive(final AbstractChannelHandlerContext next) {
        EventExecutor executor = next.executor();
        if (executor.inEventLoop()) {
            next.invokeChannelActive();
        } else {
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    next.invokeChannelActive();
                }
            });
        }
    }

AbstractChannelHandlerContext

AbstractChannelHandlerContext:

    private void invokeChannelActive() {
        if (invokeHandler()) {
            try {
                ((ChannelInboundHandler) handler()).channelActive(this);
            } catch (Throwable t) {
                notifyHandlerException(t);
            }
        } else {
            fireChannelActive();
        }
    }

这里handler()指的是head。
HeadContext的channelActive实现

        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            ctx.fireChannelActive(); // 传递channelActive事件

            readIfIsAutoRead();
        }

        private void readIfIsAutoRead() {
            if (channel.config().isAutoRead()) {  // true
                channel.read();
            }
        }

HeadContext的处理是首先将channelActive事件传递给下一个inbound,随后调用readIfIsAutoReadchannel.config().isAutoRead()true,跟踪read
AbstractChannel

    public Channel read() {
        pipeline.read();
        return this;
    }

DefaultChannelPipeline

    public final ChannelPipeline read() {
        tail.read();
        return this;
    }

调用了tailread
AbstractChannelHandlerContext

    public ChannelHandlerContext read() {
    // 从tail往前找第一个outBound
        final AbstractChannelHandlerContext next = findContextOutbound();
        EventExecutor executor = next.executor();
        if (executor.inEventLoop()) {
            next.invokeRead();
        } else {
            Runnable task = next.invokeReadTask;
            if (task == null) {
                next.invokeReadTask = task = new Runnable() {
                    @Override
                    public void run() {
                        next.invokeRead();
                    }
                };
            }
            executor.execute(task);
        }

        return this;
    }

    private AbstractChannelHandlerContext findContextOutbound() {
        AbstractChannelHandlerContext ctx = this; // 指tail
        do {
            ctx = ctx.prev;
        } while (!ctx.outbound);
        return ctx;
    }

tail往前找第一个outBound,调用其invokeRead,以上面选取的阶段为例,head->ServerBootstrapAcceptor->tail,tail前的第一个outBoundhead implements ChannelOutboundHandler, ChannelInboundHandler,它的invokeRead()实现在AbstractChannelHandlerContext

AbstractChannelHandlerContext:

    private void invokeRead() {
        if (invokeHandler()) {
            try {
                ((ChannelOutboundHandler) handler()).read(this);
            } catch (Throwable t) {
                notifyHandlerException(t);
            }
        } else {
            read();
        }
    }

调用其本身的read(ChannelHandlerContext ctx)

HeadContext:

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

对于NioServerSocketChannel它的unsafe指的是NioMessageUnsafebeginRead方法实现在AbstractUnsafe

AbstractUnsafe:
        public final void beginRead() {
            assertEventLoop();

            if (!isActive()) {
                return;
            }

            try {
                doBeginRead();
            } catch (final Exception e) {
                invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        pipeline.fireExceptionCaught(e);
                    }
                });
                close(voidPromise());
            }
        }

首先isActive()由于选取的阶段是服务端启动,定位到NioServerSocketChannel里的实现

    public boolean isActive() {
        return javaChannel().socket().isBound();
    }
    
java.net.ServerSocket:
    /**
     * Returns the binding state of the ServerSocket.
     *
     * @return true 成功绑定地址返回true
     * @since 1.4
     */
    public boolean isBound() {
        // Before 1.3 ServerSockets were always bound during creation
        return bound || oldImpl;
    }

成功绑定地址isActive才会返回true。而由于我们选取的阶段时绑定成功后,所以代码执行到这里返回true,doBeginRead()调用。

AbstractNioMessageChannel:
    protected void doBeginRead() throws Exception {
        if (inputShutdown) {
            return;
        }
        super.doBeginRead();
    }
    
AbstractNioChannel:
    protected void doBeginRead() throws Exception {
        // Channel.read() or ChannelHandlerContext.read() was called
        final SelectionKey selectionKey = this.selectionKey;
        if (!selectionKey.isValid()) {
            return;
        }

        readPending = true;

        final int interestOps = selectionKey.interestOps();
        if ((interestOps & readInterestOp) == 0) {
            selectionKey.interestOps(interestOps | readInterestOp);
        }
    }

对于一个SelectionKey它的isValid()为true是从其被创建开始一直到它被cancelled或者channel关闭或者Selector关闭位置。
readInterestOp对于NioServerSocketChannelOP_ACCEPT,对于NioSocketChannelOP_READ。上述代码做的是当相应channel关心的事件被删除则恢复它。
总结一下:我们选取的阶段是绑定完成后的fireChannelActive的调用,一路分析到这,发现该方法在此阶段的调用目的就是设置NioServerSocketChannel的关心事件为ACCEPT

在上面HeadContext的channelActive方法中,首先是将channelActive事件传递给下一个inbound,此时pipeline里情况是head->ServerBootstrapAcceptor->tail,下个inbound是ServerBootstrapAcceptor,跟踪发现其并不关心channelActive事件,直接将其向下传递,下一个inbound是tail

TailContext:
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            onUnhandledInboundChannelActive();
        }

        protected void onUnhandledInboundChannelActive() {
        }

没做任何处理,channelActive传到尾部就吞掉该事件。

前面分析了服务端启动阶段 invokeHandlerAddedIfNeededfireChannelRegisteredfireChannelActive所起的作用。接下来分析它们在连接阶段的作用(连接指客户端连接到来,NioSocketChannel创建过程,具体看我连接一篇的分析)。

对于连接阶段这三个方法全在register0中被调用。

invokeHandlerAddedIfNeeded:调用前NioSocketChannel的pipeline里的情况是head->ChannelInitialize(指childHandler)->tail,调用后变为head->xxx->xxx->xxx->…(指代码中我们设置的那些childHandler)->tail

fireChannelRegistered:调用各个handler的channelRegistered方法。

fireChannelActive:不同于服务端启动,连接阶段执行到这会调用fireChannelActive,因为isActive返回true,具体实现定位到NioSocketChannel

    public boolean isActive() {
        SocketChannel ch = javaChannel();
        return ch.isOpen() && ch.isConnected();
    }

channel创建既是open的,关于isConnected()连接一篇中分析过,ServerSocketChannel.accept返回的SocketChannel,其在创建过程中状态被赋值为2,即CONNECTED,所以isActive()返回true。
一开始过程与上面的分析一样,直到从tail往前找第一个outBound,调用其invokeRead,多数outbound的read实现只是将事件往前传,如LengthFieldPrepender,MessageToByteEncoder,IdleStateHandler等,所以如服务端一样最终传到head,head的实现调用unsafe.beginRead();,对于NioSocketChannel它的unsafe指的是NioSocketChannelUnsafe,跟踪发现其实现与上面服务端的一样,只是这里恢复的是NioSocketChannel的OP_READ事件。

连接阶段出现的fireChannelReadfireChannelReadComplete,以及其它一些将在下一篇介绍。

猜你喜欢

转载自blog.csdn.net/sinat_34976604/article/details/85133185