Channel的注册流程分析

AbstractBootStrap类的initAndRegister()方法中,先进行对Channel的初始化,在初始化过程结束之后,会执行Channel的注册流程逻辑。如下图:
Channel的注册流程分析_第1张图片
上图所示源码中,ChannelFuture regFuture = config().group().register(channel);执行Channel注册到EventLoop 上的流程。

1. config()方法

先看该行代码中的第一个方法config()
在这里插入图片描述
该方法是一个抽象方法,返回的是AbstractBootstrapConfig类,它可以获取到bootstrap的当前配置。该抽象方法在AbstractBootstrapConfig的子类BootstrapServerBootstrap中实现。这里着重看一下ServerBootStrap中的实现:
Channel的注册流程分析_第2张图片
返回了一个成员变量config,在这里插入图片描述
是一个ServerBootstrapConfig类,该类包含了ServerBootstrap的所有配置。

2.group()方法

Channel的注册流程分析_第3张图片
该方法返回一个已经配置的EventLoopGroup类,如果还未配置,则返回null

3.register(Channel channel)方法

在这里插入图片描述
在该EventLoop方法上注册一个Channel,注册完成后,返回的ChannelFuture将收到通知。因为NioEventLoopGroup继承了MultiThreadEventLoopGroup,所以在使用NioEventLoopGroup进行编程时,框架内部调用的是MultiThreadEventLoopGroupregister方法。
在这里插入图片描述

3.1 next()方法

在这里插入图片描述
next()方法返回一个EventLoop,内部调用了父类的next()方法。看一下父类MultithreadEventExecutorGroupnext()方法。
Channel的注册流程分析_第4张图片
又调用了chooser.next()chooser是个啥玩意呢?继续看源码:
在这里插入图片描述
这玩意是一个工厂类中的内部类:
Channel的注册流程分析_第5张图片
里面就一个方法next(),用来创建一个新的EventExecutor。这个EventExecutorChooserFactory有一个实现类DefaultEventExecutorChooserFactory,该类主要使用简单轮询方法选择下一个Executor,里面的newChooser()方法是这样实现的:
Channel的注册流程分析_第6张图片
意思就是如果参数的长度是2的幂,那么就返回一个PowerOfTwoEventExecutorChooser,否则就返回一个GenericEventExecutorChooser,主要是用于提升性能,这里也可以看出netty这个框架对于性能的追求已经趋于极致了,这么小的细节都考虑到了性能问题。
在这里插入图片描述
看一下GenericEventExecutorChooser.next()方法的实现,实际上就是在对Executor[]的长度取模。找下一个EventExecutor

3.2 next().register()

在上面我们看到在开始执行注册流程时调用的是 MultiThreadEventLoopGroup.register() 方法,其内部调用了next().register(channel)方法,这里next()返回一个EventLoop,也就是调用了EventLoop.register,具体实现方法是SingleThreadEventLoopGroup.register()
Channel的注册流程分析_第7张图片
随后执行SingleThreadEventLoopGroup重载的一个register()方法:
Channel的注册流程分析_第8张图片
先检查传入的参数是否为nullpromise.channel().unsafe()返回一个Unsafe,执行底层的register()方法,该方法实现在AbstractChannel中的内部类AbstractUnsafe中。

     @Override
        public final void register(EventLoop eventLoop, final ChannelPromise promise) {
            //1.检查eventLoop是否为空
            if (eventLoop == null) {
                throw new NullPointerException("eventLoop");
            }
            //2.检查是否已经注册,如果已经注册,抛出异常
            if (isRegistered()) {
                promise.setFailure(new IllegalStateException("registered to an event loop already"));
                return;
            }
            //3.检查参数是否是给定类的实例或是其子类的实例
            if (!isCompatible(eventLoop)) {
                promise.setFailure(
                        new IllegalStateException("incompatible event loop type: " + eventLoop.getClass().getName()));
                return;
            }
			
            AbstractChannel.this.eventLoop = eventLoop;
			//4.检查执行的线程是否是当前的线程,如果是则不存在并发问题,
			//如果不是当前线程则则将注册流程放到任务队列中执行
            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);
                }
            }
        }

接下来看register0():

  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;
                //register的具体实现
                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);
                //调用下一个channelInboundHandler的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.
                //所谓isActive就是指Channel处于活动 状态,已经连接或者绑定并且已经就绪
                if (isActive()) {
                    if (firstRegistration) {
                    //调用下一个channelInbooundHandler的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);
            }
        }

可以看到,有一个doRegister()方法,该方法定义在AbstractChannel在这里插入图片描述
具体实现在其子类中,这里着重看AbstractNioChannel中的实现:


    @Override
    protected void doRegister() throws Exception {
        boolean selected = false;
        for (;;) {
            try {
            //1.javaChannel()返回java nio中的SelectableChannel,
            //eventLoop().unwrappedSelector()返回jdk中的Selector
            
                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;
                }
            }
        }
    }

这段代码终于看到Java Nio的身影了.将channel注册到Selector上。

你可能感兴趣的:(Netty源码)