1. 前面说ServerBootstrap的bind(port)方法内部主要分为注册阶段(initAndRegister)和绑定阶段(doBind0),在前面我们已经分析了注册阶段(即:NioServerSocketChannel如何注册到NioEventLoop中的Selector),这一章将分析绑定阶段(doBind0)
    class AbstractBootstrap {
    private ChannelFuture doBind(final SocketAddress localAddress) {
        ChannelFuture regFuture = initAndRegister(); // 初始化Channel并注册
        Channel channel = regFuture.channel();
        if (regFuture.isDone()) {                    // 注册Channel完成,调用doBind0绑定
            ChannelPromise promise = channel.newPromise();
            doBind0(regFuture, channel, localAddress, promise);
            return promise;
        } else {                                     // 注册Channel未完成,添加操作完成监听并调用doBind0绑定
            final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
            regFuture.addListener(new ChannelFutureListener() 
                public void operationComplete(ChannelFuture future) throws Exception {
                    Throwable cause = future.cause();
                    if (cause != null) {
                        promise.setFailure(cause);
                    } else {
                        promise.registered();
                        doBind0(regFuture, channel, localAddress, promise);
                    }
                }
            });
            return promise;
        }
    }
    }
  2. doBind0内部会获取到该channel绑定的eventLoop并提交任务进行异步绑定。根据内部判断逻辑,只有regFuture.isSuccess()才会进行绑定,即只有注册成功之后才会执行绑定操作。
    class AbstractBootstrap {
    private static void doBind0(
            final ChannelFuture regFuture,
            final Channel channel,
            final SocketAddress localAddress,
            final ChannelPromise promise) {
        channel.eventLoop().execute(new Runnable() {
            public void run() {
                if (regFuture.isSuccess()) {
                    channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
                } else {
                    promise.setFailure(regFuture.cause());
                }
            }
        });
    }
    }
  3. 当eventLoop轮询线程获取到bind任务时,对于Channel来说可视为发生一次出栈事件。Channel会从其pipeline的tail开始查找首个覆写了bind方法的outBoundHandler(即: 找到headContext)然后调用其bind()方法。。
    class AbstractChannel {
    public ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
        return pipeline.bind(localAddress, promise);
    }
    }
    class DefaultChannelPipeline {
    public final ChannelFuture bind(SocketAddress localAddress, ChannelPromise promise) {
        return tail.bind(localAddress, promise);
    }
    }
    class AbstractChannelHandlerContext {
    public ChannelFuture bind(final SocketAddress localAddress, final ChannelPromise promise) {
        final AbstractChannelHandlerContext next = findContextOutbound(MASK_BIND); // 找到首个覆写了bind方法的handler
        EventExecutor executor = next.executor();
        if (executor.inEventLoop()) {
            next.invokeBind(localAddress, promise) {   // 调用bind方法
                ((ChannelOutboundHandler) handler()).bind(this, localAddress, promise)
            }
        } else {
            safeExecute(executor, new Runnable() {
                public void run() {
                    next.invokeBind(localAddress, promise);
                }
            }, promise, null, false);
        }
        return promise;
    }
    }
  4. 在headContext覆写的bind方法中,调用了doBind()方法,内部调用了原生JavaNio的bind方法进行绑定。在doBind()成功之后,会提交个异步任务(invokeLater),来触发channelActive。在active内部进行注册了channel的interestOps。
    class AbstractChannelHandlerContext {
    public final void bind(final SocketAddress localAddress, final ChannelPromise promise) {
        boolean wasActive = isActive();
        doBind(localAddress) {
            javaChannel().bind(localAddress, config.getBacklog());
        }
        // 完成绑定之后还做了其它事情,这里会递归调用pipeline上所有handler的channelActive方法
        if (!wasActive && isActive()) {
            invokeLater(new Runnable() {
                public void run() {
                    pipeline.fireChannelActive() {
                        ((ChannelInboundHandler) handler()).channelActive(this);
                    }
                }
            });
        }
        safeSetSuccess(promise);
    }
    }

    总结:

    serverBootstrap的bind(port)方法:
    sb.bind( port )
    |__ doBind()
    |__ initAndRegister()
        |__ ...
    |__ bind0()
        |__ channel.eventLoop().execute( bind() )
            |__ nioEventLoop.run()
                |__ bind()
                    |__ doBind()
                    |__ eventLoop().execute( fireChannelActive() )
                |__ fireChannelActive()