初始化完成之后,就是把创建的channel注册到事件轮询器selector上面去。

注册到selector上主要做以下两件事情:

1、绑定eventLoop,这个eventLoop就是服务端的event,不是childEventLoop[绑定线程]

2、registor0做实际的注册

    2.1、doRegister(),调用jdk底层注册

    2.2、invokeHandlerAddedIfNeeded()(主要做一些事件的回调)

    2.3、fireChannelRegistered(),传播事件

回到《netty源码阅读之服务器启动之服务端channel的创建》这盘文章的AbstractBootstrap的initAndRegister方法,里面有一段代码,这是在创建和初始化完成channel之后的一段代码,register的

ChannelFuture regFuture = config().group().register(channel);

这个register方法层层追溯,可以到达AbstractChannel里面内部类的AbstractUnsafe的register方法(这个方法就是接下去我们要分析的方法):

@Override
        public final void register(EventLoop eventLoop, final ChannelPromise promise) {
            if (eventLoop == null) {
                throw new NullPointerException("eventLoop");
            }
            if (isRegistered()) {
                promise.setFailure(new IllegalStateException("registered to an event loop already"));
                return;
            }
            if (!isCompatible(eventLoop)) {
                promise.setFailure(
                        new IllegalStateException("incompatible event loop type: " + eventLoop.getClass().getName()));
                return;
            }

            AbstractChannel.this.eventLoop = eventLoop;

            if (eventLoop.inEventLoop()) {
                register0(promise);
            } else {
                try {
                    eventLoop.execute(new Runnable() {
                        @Override
                        public void run() {
                            register0(promise);
                        }
                    });
                } catch (Throwable t) {
                    logger.warn(
                            "Force-closing a channel whose registration task was not accepted by an event loop: {}",
                            AbstractChannel.this, t);
                    closeForcibly();
                    closeFuture.setClosed();
                    safeSetFailure(promise, t);
                }
            }
        }

绑定线程用的就是AbstractChannel.this.eventLoop = eventLoop,也就是把nio线程和当前的channel做绑定。

后续所有的io操作,都是通过这个eventLoop来处理。

从用户代码的b.group(bossGroup, workerGroup)追溯,这个eventLoop就是和bossGroup有千丝万缕的关系。

 

然后我们看register0(),点进去,在AbstractChannl里面有个这样的函数:

private void register0(ChannelPromise promise) {
            try {
                // check if the channel is still open as it could be closed in the mean time when the register
                // call was outside of the eventLoop
                if (!promise.setUncancellable() || !ensureOpen(promise)) {
                    return;
                }
                boolean firstRegistration = neverRegistered;
                doRegister();
                neverRegistered = false;
                registered = true;

                // Ensure we call handlerAdded(...) before we actually notify the promise. This is needed as the
                // user may already fire events through the pipeline in the ChannelFutureListener.
                pipeline.invokeHandlerAddedIfNeeded();

                safeSetSuccess(promise);
                pipeline.fireChannelRegistered();
                // Only fire a channelActive if the channel has never been registered. This prevents firing
                // multiple channel actives if the channel is deregistered and re-registered.
                if (isActive()) {
                    if (firstRegistration) {
                        pipeline.fireChannelActive();
                    } else if (config().isAutoRead()) {
                        // This channel was registered before and autoRead() is set. This means we need to begin read
                        // again so that we process inbound data.
                        //
                        // See https://github.com/netty/netty/issues/4805
                        beginRead();
                    }
                }
            } catch (Throwable t) {
                // Close the channel directly to avoid FD leak.
                closeForcibly();
                closeFuture.setClosed();
                safeSetFailure(promise, t);
            }
        }

在这里register0又做了三件事:

1、doRegister(),调用jdk底层注册

2、invokeHandlerAddedIfNeeded()

3、fireChannelRegistered(),传播事件

选择AbstractNioChannel的doregister()

@Override
    protected void doRegister() throws Exception {
        boolean selected = false;
        for (;;) {
            try {
                selectionKey = javaChannel().register(eventLoop().selector, 0, this);
                return;
            } catch (CancelledKeyException e) {
                if (!selected) {
                    // Force the Selector to select now as the "canceled" SelectionKey may still be
                    // cached and not removed because no Select.select(..) operation was called yet.
                    eventLoop().selectNow();
                    selected = true;
                } else {
                    // We forced a select operation on the selector before but the SelectionKey is still cached
                    // for whatever reason. JDK bug ?
                    throw e;
                }
            }
        }
    }

这里就是调用jdk底层channel的register方法将jdk底层channel注册到selector轮询器上,并把NioServerSocketChannel自己作为attachment给添加进去。

javaChannel就是我们之前创建的jdk底层的channel;register就是调用jdk的api,参数第一个是selector,第二个是ops(需要关心的一些事件,0代表不关心任何事件,只是把channel绑定到selector上面去),第三个是attachment,也是把自己this也就是服务端channel作为attachment绑定到selector上面去(后面如果selector轮询到事件,可以直接把attachment也就是把netty的channel拿出来,然后针对这个nioChannel可以做一些事件的传播)。

 

在定义用户代码Handler,有这三个回调:

public void channelActive(ChannelHandlerContext ctx) {
        System.out.println("channelActive");
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) {
        System.out.println("channelRegistered");
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) {
        System.out.println("handlerAdded");
    }

有两个回调,就是在这里被调用了,先输出handleAdd然后输出handleRegistered。至于channelActive这个回调,是在端口绑定之后被回调的。此时的isActive()还是false。现在只有做了selector的注册,只有最终绑定端口之后,才会回调这个方法。下一篇文章我们会介绍。