初始化完成之后,就是把创建的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的注册,只有最终绑定端口之后,才会回调这个方法。下一篇文章我们会介绍。