在AbstractBootStrap
类的initAndRegister()
方法中,先进行对Channel
的初始化,在初始化过程结束之后,会执行Channel
的注册流程逻辑。如下图:
上图所示源码中,ChannelFuture regFuture = config().group().register(channel);
执行Channel
注册到EventLoop
上的流程。
config()
方法先看该行代码中的第一个方法config()
:
该方法是一个抽象方法,返回的是AbstractBootstrapConfig
类,它可以获取到bootstrap
的当前配置。该抽象方法在AbstractBootstrapConfig
的子类Bootstrap
和ServerBootstrap
中实现。这里着重看一下ServerBootStrap
中的实现:
返回了一个成员变量config
,
是一个ServerBootstrapConfig
类,该类包含了ServerBootstrap
的所有配置。
group()
方法
该方法返回一个已经配置的EventLoopGroup
类,如果还未配置,则返回null
。
register(Channel channel)
方法
在该EventLoop
方法上注册一个Channel
,注册完成后,返回的ChannelFuture
将收到通知。因为NioEventLoopGroup
继承了MultiThreadEventLoopGroup
,所以在使用NioEventLoopGroup
进行编程时,框架内部调用的是MultiThreadEventLoopGroup
的register
方法。
next()
方法
next()
方法返回一个EventLoop
,内部调用了父类的next()
方法。看一下父类MultithreadEventExecutorGroup
的next()
方法。
又调用了chooser.next()
,chooser
是个啥玩意呢?继续看源码:
这玩意是一个工厂类中的内部类:
里面就一个方法next()
,用来创建一个新的EventExecutor
。这个EventExecutorChooserFactory
有一个实现类DefaultEventExecutorChooserFactory
,该类主要使用简单轮询方法选择下一个Executor
,里面的newChooser()
方法是这样实现的:
意思就是如果参数的长度是2的幂,那么就返回一个PowerOfTwoEventExecutorChooser
,否则就返回一个GenericEventExecutorChooser
,主要是用于提升性能,这里也可以看出netty这个框架对于性能的追求已经趋于极致了,这么小的细节都考虑到了性能问题。
看一下GenericEventExecutorChooser.next()
方法的实现,实际上就是在对Executor[]
的长度取模。找下一个EventExecutor
next().register()
在上面我们看到在开始执行注册流程时调用的是 MultiThreadEventLoopGroup.register()
方法,其内部调用了next().register(channel)
方法,这里next()
返回一个EventLoop
,也就是调用了EventLoop.register
,具体实现方法是SingleThreadEventLoopGroup.register()
,
随后执行SingleThreadEventLoopGroup
重载的一个register()
方法:
先检查传入的参数是否为null
,promise.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
上。