概述
在netty的bind方法里,经过 channel(NioServerSocketChannel) 的实例化后初始化后,开始向pipeline里添加 handler,然后还会调用register向 bossGroup 里面注册 channel(NioServerSocketChannel),但是这里只会先将这个register0 方法作为一个任务放入任务队列中,然后就会开启reactor ,接着这个线程就会开始执行之前的任务队列,就会执行register0
register0()
private void register0(ChannelPromise promise) {
try {
if (!promise.setUncancellable() || !ensureOpen(promise)) {
return;
}
boolean firstRegistration = neverRegistered;
doRegister();
neverRegistered = false;
registered = true;
pipeline.invokeHandlerAddedIfNeeded();
safeSetSuccess(promise);
//会执行channelRegistered
pipeline.fireChannelRegistered();
if (isActive()) {
if (firstRegistration) {
pipeline.fireChannelActive();
} else if (config().isAutoRead()) {
beginRead();
}
}
} catch (Throwable t) {
closeForcibly();
closeFuture.setClosed();
safeSetFailure(promise, t);
}
}
真正的核心的注册方法是 doRegister();
@Override
protected void doRegister() throws Exception {
boolean selected = false;
for (;;) {
try {
selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
return;
} catch (CancelledKeyException e) {
if (!selected) {
eventLoop().selectNow();
selected = true;
} else {
throw e;
}
}
}
}
虽然这个方法是一个for循环,但是只执行一次就会return
看细节
private final SelectableChannel ch;
protected SelectableChannel javaChannel() {
return ch;
}
这个变量在笔者之前的netty博客中分析过,这个就是原生的 jdk 的ServerSocketChannel (ServerSocketChannelImpl)
仔细看一看,这里是不是和 jdk 原生的 Nio 很像呢?
eventLoop():就是获取 NioEventLoop 对象,然后通过这个对象获取到这个 NioEventLoop 的选择器(Selector),然后将感兴趣的事件注册到选择器上,但是目前这里是传了 0 ,也就是对任何事件都不感兴趣,所以仅仅只是将这个ServerSocketChannel 注册到了Selector上面而已,然后就return了
还有一点需要注意的是这里的register多传入了一个参数,为什么要传入这个参数呢?
因为netty在接收连接的时候最终调用的依然是Nio的 API 而这个传入的对象是 NioServerSocketChannel 类型 这里面有个属性 ch 其保存的就是JDK原生的 ServerSocketChannel(ServerSocketChannelImpl),也就是说,当有客户端连接的时候就会去获取这个对象,操作原生的
ServerSocketChannel
注册完成后来到 pipeline.invokeHandlerAddedIfNeeded()
final void invokeHandlerAddedIfNeeded() {
assert channel.eventLoop().inEventLoop();
if (firstRegistration) {
firstRegistration = false;
callHandlerAddedForAllHandlers();
}
}
private void callHandlerAddedForAllHandlers() {
final PendingHandlerCallback pendingHandlerCallbackHead;
synchronized (this) {
assert !registered;
registered = true;
pendingHandlerCallbackHead = this.pendingHandlerCallbackHead;
this.pendingHandlerCallbackHead = null;
}
PendingHandlerCallback task = pendingHandlerCallbackHead;
while (task != null) {
task.execute();
task = task.next;
}
}
这里使用 firstRegistration (默认为true)这个变量保证这个方法只会执行一次
然后在callHandlerAddedForAllHandlers 中 会获取一个pendingHandlerCallbackHead的属性,这个属性是什么呢???
这个属性的类型是 PendingHandlerCallback 类型,这里不知道大家是否有印象,在笔者之前的博客中的addLast方法中,将传入的ChannelInitializer封装成PendingHandlerAddedTask ,这里的pendingHandlerCallbackHead 属性就是这个对象
接着来到execute()
void execute() {
EventExecutor executor = ctx.executor();
if (executor.inEventLoop()) {
callHandlerAdded0(ctx);
} else {
try {
executor.execute(this);
} catch (RejectedExecutionException e) {
if (logger.isWarnEnabled()) {
...
executor, ctx.name(), e);
}
remove0(ctx);
ctx.setRemoved();
}
}
}
ctx.executor() 返回的是 NioEventLoop ,然后调用inEventLoop(),执行到这里Reactor线程已经启动了,所以这里一定是为true
追溯callHandlerAdded0(ctx)
final void callHandlerAdded() throws Exception {
if (setAddComplete()) {
handler().handlerAdded(this);
}
}
setAddComplete() : 是修改handler的状态变量判断handlerState等于1
handler() : 获取ChannelInitializer 对象
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
if (ctx.channel().isRegistered()) { 判断这个channel是否已经注册,这里当然是注册过的
if (initChannel(ctx)) {
removeState(ctx);
}
}
}
private boolean initChannel(ChannelHandlerContext ctx) throws Exception {
if (initMap.add(ctx)) {
try {
initChannel((C) ctx.channel());
} catch (Throwable cause) {
exceptionCaught(ctx, cause);
} finally {
//删除此节点
ChannelPipeline pipeline = ctx.pipeline();
if (pipeline.context(this) != null) {
pipeline.remove(this);
}
}
return true;
}
return false;
}
获取到当前对应的handler (ChannelInitializer),这个initChannel()方法调用的就是 ChannelInitializer 的 initChannel
并且当执行完这个handler之后,在finally中还会将这个节点从pipeline 中 删除
回到这个内部的 handler 继续进行分析
p.addLast(new ChannelInitializer<Channel>() {
@Override
public void initChannel(final Channel ch) throws Exception {
final ChannelPipeline pipeline = ch.pipeline();
ChannelHandler handler = config.handler();
if (handler != null) {
pipeline.addLast(handler);
}
ch.eventLoop().execute(new Runnable() {
@Override
public void run() {
pipeline.addLast(new ServerBootstrapAcceptor(
ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}
});
}
});
调用了config.handler() 这个handler返回的是什么呢?这里返回的其实是我们自己添加的handler,也就是通过handler()方法添加的handler,然后又是addLast()方法进行添加,也就是说我们自己写的handler就是在这里进行添加的
在这个方法的最后又向任务队列里面加了一个任务,这个任务又是去pipeline里面添加一个Handler,这个handler就是与客户端连接相关了,会在笔者后续文章介绍