3-4 注册selector

一  注册selector大纲

 1.  AbstractChannel.register(channel)  //入口

 2.  this.eventLoop = eventLoop  //绑定线程

 3.  register0()  //实际注册

 4.register0()调用流程

  doRegister()  //调用jdk底层的注册方法

  fireChannelRegistered()  //调用传播事件

 

二  注册selector流程

 1. 进入 AbstractChannel.register(channel)  

       //channel 注册入口
        @Override
        public final void register(EventLoop eventLoop, final ChannelPromise promise) {
            ObjectUtil.checkNotNull(eventLoop, "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;
            }

            //设置eventLoop
            AbstractChannel.this.eventLoop = eventLoop;

            if (eventLoop.inEventLoop()) {
                //channel 实际注册方法
                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.register(channel)  方法很简单,先保存eventLoop,然后调用 AbstractUnsafe#register0 方法继续注册 ChannelFuture

 

 进入 AbstractUnsafe#register0 方法

        //注册 channel
        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;
                /**
                 * 调用 {@link AbstractNioChannel#doRegister()} 注册
                 */
                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.
                //调用 ChannelHandler 的 handlerAdded 方法
                pipeline.invokeHandlerAddedIfNeeded();

                safeSetSuccess(promise);
                // 触发 channelRegistered 事件
                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) {
                        // 触发 channelActive 事件
                        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);
            }
        }

 AbstractUnsafe#register0 方法继续调用 AbstractNioChannel#doRegister() 方法注册,接着按顺序触发 handlerAdded、channelRegistered、channelActive 事件

 

 进入 AbstractNioChannel#doRegister() 方法

    @Override
    protected void doRegister() throws Exception {
        boolean selected = false;
        for (;;) {
            try {
                //调用 nio 的channel 注册 Selector,这里可以看出 register 保存的 attachment 为当前 AbstractNioChannel
                selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 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;
                }
            }
        }
    }

 AbstractNioChannel#doRegister() 方法就调用 jdk 底层的 nio 的 channel 注册了 selector,并且从这里可以看出 register 保存的 attachment 为当前 AbstractNioChannel,这在后续的 processSelectionKey 中会用到

 

 至此注册selector 结束,注册selector 很简单,主要就以下几步

  1. 保存 eventLoop
  2. 调用 jdk 底层的 nio 的 channel 注册了 selector
  3. 依次触发 handlerAdded、channelRegistered、channelActive 事件
posted @ 2019-11-24 22:33  programmLover  阅读(166)  评论(0)    收藏  举报