一、Netty启动流程源码
上一篇文章中的Netty服务端启动代码中,bind()方法才是Netty真正开始启动的地方。跟踪代码,会进入AbstractBootstrap#doBind()方法
private ChannelFuture doBind(final SocketAddress localAddress) {
//初始化并注册一个channel
final ChannelFuture regFuture = initAndRegister();
final Channel channel = regFuture.channel();
if (regFuture.cause() != null) {
return regFuture;
}
//等待注册成功
if (regFuture.isDone()) {
// At this point we know that the registration was complete and successful.
ChannelPromise promise = channel.newPromise();
//执行channel.bind()
doBind0(regFuture, channel, localAddress, promise);
return promise;
} else {
// Registration future is almost always fulfilled already, but just in case it's not.
final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
regFuture.addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
Throwable cause = future.cause();
if (cause != null) {
// Registration on the EventLoop failed so fail the ChannelPromise directly to not cause an
// IllegalStateException once we try to access the EventLoop of the Channel.
promise.setFailure(cause);
} else {
// Registration was successful, so set the correct executor to use.
// See https://github.com/netty/netty/issues/2586
promise.executor = channel.eventLoop();
}
doBind0(regFuture, channel, localAddress, promise);
}
});
return promise;
}
}
1、NioServerSocketChannel的初始化:
AbstractBootstrap#initAndRegister
final ChannelFuture initAndRegister() {
// 还记得前面我们设置过channel工厂么,终于派上用场了
final Channel channel = channelFactory().newChannel();
try {
//初始化channel(就是NioServerSocketChannel)
init(channel);
} catch (Throwable t) {
channel.unsafe().closeForcibly();
// as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
}
// 向EventLoopGroup - BossGroup中注册一个channel
ChannelFuture regFuture = group().register(channel);
if (regFuture.cause() != null) {
if (channel.isRegistered()) {
channel.close();
} else {
channel.unsafe().closeForcibly();
}
}
return regFuture;
}
ServerBootstrap#init:
void init(Channel channel) throws Exception {
*******
// 获取channel绑定的pipeline(pipeline实在channel创建的时候创建并绑定的)
ChannelPipeline p = channel.pipeline();
// 如果用户配置过Handler,为NioServerSocketChannel绑定的pipeline添加Handler
if (handler() != null) {
p.addLast(handler());
}
//开始准备WorkerGroup用到的4个part,因为接下来就要使用它们。
final EventLoopGroup currentChildGroup = childGroup;
final ChannelHandler currentChildHandler = childHandler;
final Entry<ChannelOption<?>, Object>[] currentChildOptions;
final Entry<AttributeKey<?>, Object>[] currentChildAttrs;
synchronized (childOptions) {
currentChildOptions = childOptions.entrySet().toArray(newOptionArray(childOptions.size()));
}
synchronized (childAttrs) {
currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(childAttrs.size()));
}
// 为NioServerSocketChannel的pipeline添加一个初始化Handler,
// 当NioServerSocketChannel在EventLoop注册成功时,该handler的init方法将被调用
p.addLast(new ChannelInitializer<Channel>() {
@Override
public void initChannel(Channel ch) throws Exception {
// 为NioServerSocketChannel的pipeline添加一个Handler:ServerBootstrapAcceptor处理器
// 该Handler主要用来监听channelRead事件,将新产生的channel绑定到WorkerGroup中的某个EventLoop
ch.pipeline().addLast(new ServerBootstrapAcceptor(
currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
}
});
}
由上段代码可知,正是在此处将BossGroup、WorkerGroup关联起来,BossGroup主要是监听Accept事件,WorkerGroup主要是监听Read/Write事件,分工明确!ServerBootstrapAcceptor 这个Handler的作用具体体现在Netty线程模型的红线标注的地方:
NioServerSocketChannel执行完init()方法之后,再来看下NioServerSocketChannel是如何注册到NioEventLoop中的Selector上的。
2、NioServerSocketChannel的注册
// 向EventLoopGroup - BossGroup中注册一个channel
ChannelFuture regFuture = group().register(channel);
先看下调用链:
MultithreadEventLoopGroup#register(io.netty.channel.Channel)
-> SingleThreadEventLoop#register(io.netty.channel.Channel)
-> SingleThreadEventLoop#register(io.netty.channel.ChannelPromise)
-> AbstractChannel.AbstractUnsafe#register
->AbstractChannel.AbstractUnsafe#register0
AbstractChannel.AbstractUnsafe#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;
//最底层的注册调用
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会触发init时添加的Handler-ChannelInitializer
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);
}
}
AbstractNioChannel#doRegister
protected void doRegister() throws Exception {
boolean selected = false;
for (;;) {
try {
// 完成在EventLoop的Selector上的注册
// 注意,此时op位为0,channel还不能监听读写事件
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;
}
}
}
}
3、NioEventLoop的调用
在服务端启动流程中当执行到注册操作时,会判断当前线程是否是ServerSocketChannel所绑定的NioEventLoop中的线程,如果不是的话,会将注册操作封装成一个线程任务交给NioEventLoop中的线程去执行,相关代码如下所示:
AbstractChannel.AbstractUnsafe#register:
@Override
public final void register(EventLoop eventLoop, final ChannelPromise promise) {
******
AbstractChannel.this.eventLoop = eventLoop;
// 判断当前线程是否是ServerSocketChannel所绑定的线程EventLoop中的线程
// 由于目前处于启动阶段,当前线程是main线程,所以inEventLoop应为false
if (eventLoop.inEventLoop()) {
register0(promise);
} else {
try {
// 调用eventLoop.execute(Runnable runnable)方法将任务提交给eventLoop执行。
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);
}
}
}
相关逻辑在父类SingleThreadEventxecutor类中实现:
public void execute(Runnable task) {
if (task == null) {//合法性校验
throw new NullPointerException("task");
}
// 判断当前线程是否是ServerSocketChannel所绑定的线程EventLoop中的线程
// 由于目前处于启动阶段,当前线程是main线程,所以inEventLoop应为false
boolean inEventLoop = inEventLoop();
//将线程任务添加到EventLoop中的任务队列
addTask(task);
if (!inEventLoop) {
// 启动线程
startThread();
// 如果线程已经关闭则移除上面提交到任务队列中的任务,并调用拒绝策略,拒绝任务的执行
if (isShutdown() && removeTask(task)) {
reject();
}
}
if (!addTaskWakesUp && wakesUpForTask(task)) {
wakeup(inEventLoop);
}
}
SingleThreadEventExecutor#doStartThread
private void doStartThread() {
assert thread == null;
executor.execute(new Runnable() {
@Override
public void run() {
thread = Thread.currentThread();
if (interrupted) {
thread.interrupt();
}
boolean success = false;
updateLastExecutionTime();
try {
// 执行NioEventLoop的地方
SingleThreadEventExecutor.this.run();
success = true;
} catch (Throwable t) {
logger.warn("Unexpected exception from an event executor: ", t);
} finally {
for (;;) {
int oldState = state;
if (oldState >= ST_SHUTTING_DOWN || STATE_UPDATER.compareAndSet(
SingleThreadEventExecutor.this, oldState, ST_SHUTTING_DOWN)) {
break;
}
}
// Check if confirmShutdown() was called at the end of the loop.
if (success && gracefulShutdownStartTime == 0) {
if (logger.isErrorEnabled()) {
logger.error("Buggy " + EventExecutor.class.getSimpleName() + " implementation; " +
SingleThreadEventExecutor.class.getSimpleName() + ".confirmShutdown() must " +
"be called before run() implementation terminates.");
}
}
try {
// Run all remaining tasks and shutdown hooks.
for (;;) {
if (confirmShutdown()) {
break;
}
}
} finally {
try {
cleanup();
} finally {
STATE_UPDATER.set(SingleThreadEventExecutor.this, ST_TERMINATED);
threadLock.release();
if (!taskQueue.isEmpty()) {
if (logger.isWarnEnabled()) {
logger.warn("An event executor terminated with " +
"non-empty task queue (" + taskQueue.size() + ')');
}
}
terminationFuture.setSuccess(null);
}
}
}
}
});
}
上述代码中可以看到,SingleThreadEventExecutor来执行NioEventLoop的run()方法,具体run()方法的执行内容可以查看《Netty源码阅读(一)-核心组件》的第三节内容——NioEventLoop。
二、Netty启动流程总结
由上述的源码分析可知,Netty的启动流程,其实大体如下:
1、将NioServerSocketChannel初始化后,注册到BossGroup的NioEventLoop的Selector上,并且注册监听的是Accept事件。
2、BossGroup的NioEventLoop执行run()方法,循环执行Select()、processSelectedKeys()、runAllTasks()方法;
(此时NioServerSocketChannel的pipeline添加一个Handler:ServerBootstrapAcceptor处理器, 这个Handler将NioSocketChannel注册到WorkerGroup的NioEventLoop的Selector上,并且注册监听的是Read/Write事件。)
3、WorkerGroup的NioEventLoop执行run()方法,循环执行Select()、processSelectedKeys()、runAllTasks()方法。