说说Netty服务端启动流程
本文来源:http://yeming.me/2016/03/12/netty1/
netty服务端代码分析
服务端启动配置
对于 ServerBootstrap
:ServerBootstrap
继承于 AbstractBootstrap
,它从父类继承了 EventLoopGroupgroup
, ChannelFactory<?extendsC>channelFactory
,自己新增了 EventLoopGroupchildGroup
, ChannelHandlerchildHandler
。上面 b.group
开始的链式代码就是初始化上面这些属性的值的。
bossgroup
和 workergroup
:可以看到都是 NioEventLoopGroup
,可以理解成2个线程池。从 bossgroup
中随便选一个作为 Reactor
模型中的 acceptor
,监听客户端连接,创建 socketChannel
,然后从 workergroup
选取一个io线程来处理 socketChannel
的读取事件。
对于 NioEventLoopGroup
和 NioEventLoop
:先看下类图
可以看到 NioEventLoopGroup
继承了 EventLoopGroup
NioEventLoop实现了EventLoop,而EventLoop又继承自EventLoopGroup。eventloopgroup.next()又可以返回一个eventloop。可以看到EventLoop最终继承于线程池Executor。而最终NioEventLoopGroup又实现了EventLoop,接下来我们还会分析下NioEventLoopGroup
服务端注册感兴趣事件和监听端口
注册感兴趣事件
b.bind最终调用到AbstractBootstrop的以下方法
final ChannelFuture initAndRegister() {
this.group().register(channel);(中间省略)
}
这个this.group就是一开始设置的bossgroup(NioEventLoopGroup),看到这个方法基本可以想到这个应该是把channel注册到某个选择器上
MultithreadEventLoopGroup
public ChannelFuture register(Channel channel) {
return this.next().register(channel);
}
上面的类图已经可以看出 NioEventLoopGroup
继承自 MultithreadEventLoopGroup
,最终 this.next()
又会返回 NioEventLoop
,所以也就是可以理解是把 channel
注册到 NioEventLoop
上(我们猜想 NioEventLoop
可以想象成封装了一个 selector
)
this.next()返回 NioEventLoop
继承于 SingleThreadEventLoopchannel.unsafe().register(this,promise);
最终调用到 AbstractUnsafe
的 register
方法
eventLoop.execute(new OneTimeTask() {
public void run() {
AbstractUnsafe.this.register0(promise);
}
});
这里通过 bossgroup
启动一个线程
最终调用到
protected void doRegister() throws Exception {
boolean selected = false;
while(true) {
try {
this.selectionKey = this.javaChannel().register(this.eventLoop().selector, 0, this);
return;
} catch (CancelledKeyException var3) {
if(selected) {
throw var3;
}
this.eventLoop().selectNow();
selected = true;
}
}
}
监听端口
可以看到第四张截图
ChannelFuture regFuture = this.initAndRegister();
if(regFuture.cause() != null) {
return regFuture;
} else if(regFuture.isDone()) {
doBind0(regFuture, channel, localAddress, promise1); return promise1;
} else {
AbstractBootstrap.doBind0(regFuture, channel, localAddress, promise); } }); return promise;
}
可以看到 initAndRegister()
这个方法就是上面我们说的注册感兴趣的事件。后面的 elseif
和 else
都有 dobind0
方法,这个方法也是通过之前的线程池启动一个线程去监听一个端口。
参考
netty api说明http://www.boyunjian.com/javadoc/io.netty/netty-transport/4.0.0.Alpha7//io/netty/channel/DefaultChannelFuture.htmlNetty 4源码解析:服务端启动http://blog.csdn.net/dc726/article/details/47858077Netty 4源码解析:请求处理http://blog.csdn.net/dc726/article/details/48084367Netty系列之Netty线程模型(http://www.infoq.com/cn/articles/netty-threading-model?utmsource=infoq&utmmedium=popularlinks_homepage