netty源碼分析-註冊Selector

前面幾節我們分析了Channel的創建和初始化過程,都是集中在AbstractBootstrap#initAndRegister方法。在newChannel()init(channel)之後,接着的是便是註冊

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

初始化的時候配置的NioEventLoopGroup,調用的是其父類MultithreadEventLoopGroupregister()

    @Override
    public ChannelFuture register(Channel channel) {
        return next().register(channel);
    }

    @Override
    public EventLoop next() {
        return (EventLoop) super.next();
    }

next()方法獲取的是一個EventLoop,調用其父類MultithreadEventExecutorGroup#next()方法

    @Override
    public EventExecutor next() {
        return chooser.next();
    }

chooser是其成員變量,選擇器,用於選擇executors,其初始化的過程其實就是NioEventLoopGroup的初始過程,查看構造方法,一層一層往上調用,會調用到父類的父類MultithreadEventExecutorGroup#MultithreadEventExecutorGroup)

protected MultithreadEventExecutorGroup(int nThreads, Executor executor, Object... args) {
        this(nThreads, executor, DefaultEventExecutorChooserFactory.INSTANCE, args);
    }

其中初始化了一個參數DefaultEventExecutorChooserFactory.INSTANCE實例化了一個工廠,記者看構造方法,該工廠最終初始化了chooser

public static final DefaultEventExecutorChooserFactory INSTANCE = new DefaultEventExecutorChooserFactory();
protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
                                            EventExecutorChooserFactory chooserFactory, Object... args) {

//省略代碼
//根據配置的線程數,創建EventExecutor數組
 children = new EventExecutor[nThreads];

//實例化數組中具體的的EventExecutor
 for (int i = 0; i < nThreads; i ++) {
  //省略代碼
  children[i] = newChild(executor, args);
  //省略代碼
 }

//初始化Executer選擇器
chooser = chooserFactory.newChooser(children);
//省略代碼
}

查看DefaultEventExecutorChooserFactory#newChooser,發現是在根據線程數創建EventExecutor的時候,返回不同的兩個選擇器

    public EventExecutorChooser newChooser(EventExecutor[] executors) {
        if (isPowerOfTwo(executors.length)) {
            //返回一個基於2的冪次方的選擇器
            return new PowerOfTwoEventExecutorChooser(executors);
        } else {
            //返回一個通用選擇器
            return new GenericEventExecutorChooser(executors);
        }
    }

不難推斷其選擇器的next()方法是以這個爲基礎返回數組中指定的EventExecutor

    private static final class PowerOfTwoEventExecutorChooser implements EventExecutorChooser {
        private final AtomicInteger idx = new AtomicInteger();
        private final EventExecutor[] executors;

        PowerOfTwoEventExecutorChooser(EventExecutor[] executors) {
            this.executors = executors;
        }

        @Override
        public EventExecutor next() {
            return executors[idx.getAndIncrement() & executors.length - 1];
        }
    }

    private static final class GenericEventExecutorChooser implements EventExecutorChooser {
        private final AtomicInteger idx = new AtomicInteger();
        private final EventExecutor[] executors;

        GenericEventExecutorChooser(EventExecutor[] executors) {
            this.executors = executors;
        }

        @Override
        public EventExecutor next() {
            return executors[Math.abs(idx.getAndIncrement() % executors.length)];
        }
    }

要想知道是具體哪個EventExecutor,還得查看children[i] = newChild(executor, args);發現它是一個抽象方法,具體實現類是用戶註冊的NioEventLoopGroup

    @Override
    protected EventLoop newChild(Executor executor, Object... args) throws Exception {
        return new NioEventLoop(this, executor, (SelectorProvider) args[0],
            ((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2]);
    }

那麼到這裏我們發現了其實具體的EventExecutor其實是NioEventLoop,查看其register方法

    @Override
    public ChannelFuture register(Channel channel) {
        return register(new DefaultChannelPromise(channel, this));
    }

    @Override
    public ChannelFuture register(final ChannelPromise promise) {
        ObjectUtil.checkNotNull(promise, "promise");
        promise.channel().unsafe().register(this, promise);
        return promise;
    }

再進一步往下查看發現其調用的是AbstractChannel.AbstractUnsafe#register,主要乾了兩件事情,初始化通道的

        @Override
        public final void register(EventLoop eventLoop, final ChannelPromise promise) {
           //省略代碼
            //初始化eventLoop
            AbstractChannel.this.eventLoop = eventLoop;
            
          
            if (eventLoop.inEventLoop()) {
                //eventLoop與當前線程相同直接執行
                register0(promise);
            } else {
                //eventLoop與當前線程不同則獲取eventLoop的Execute再新增任務執行`register0`
                try {
                    eventLoop.execute(new Runnable() {
                        @Override
                        public void run() {
                            register0(promise);
                        }
                    });
                } 
                //省略代碼
            }
        }

register0()主要做了幾件事, 註冊,執行Event: HandlerAdded,傳遞Event: ChannelRegistered,判斷是否傳遞Event: ChannelActive

 private void register0(ChannelPromise promise) {  
                //具體的註冊
                doRegister();
                
                //執行Event: HandlerAdded
                pipeline.invokeHandlerAddedIfNeeded();
                
                //傳遞Event: ChannelRegistered
                pipeline.fireChannelRegistered();
                
                //是否傳遞Event: ChannelActive
                if (isActive()) {
                    if (firstRegistration) {
                        pipeline.fireChannelActive();
                    } else if (config().isAutoRead()) {
                        beginRead();
                    }
                }

}

doRegister()是一個空方法,應當查看其具體實現AbstractNioChannel,其中,調用了java底層的時間,註冊Selector並獲得selectionKey

    @Override
    protected void doRegister() throws Exception {
        boolean selected = false;
        for (;;) {
            try {

                //註冊到java的Selector,未綁定事件,並且獲得selectionKey
                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;
                }
            }
        }
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章