vlambda博客
学习文章列表

说说Netty服务端启动流程

点击上方☝ SpringForAll社区  轻松关注!
及时获取有趣有料的技术文章

本文来源:http://yeming.me/2016/03/12/netty1/


netty服务端代码分析

服务端启动配置

对于 ServerBootstrapServerBootstrap继承于 AbstractBootstrap,它从父类继承了 EventLoopGroupgroupChannelFactory<?extendsC>channelFactory,自己新增了 EventLoopGroupchildGroupChannelHandlerchildHandler。上面 b.group开始的链式代码就是初始化上面这些属性的值的。

bossgroupworkergroup:可以看到都是 NioEventLoopGroup,可以理解成2个线程池。从 bossgroup中随便选一个作为 Reactor模型中的 acceptor,监听客户端连接,创建 socketChannel,然后从 workergroup选取一个io线程来处理 socketChannel的读取事件。

对于 NioEventLoopGroupNioEventLoop:先看下类图

说说Netty服务端启动流程

可以看到 NioEventLoopGroup继承了 EventLoopGroup说说Netty服务端启动流程NioEventLoop实现了EventLoop,而EventLoop又继承自EventLoopGroup。eventloopgroup.next()又可以返回一个eventloop。可以看到EventLoop最终继承于线程池Executor。而最终NioEventLoopGroup又实现了EventLoop,接下来我们还会分析下NioEventLoopGroup

服务端注册感兴趣事件和监听端口

说说Netty服务端启动流程

注册感兴趣事件

b.bind最终调用到AbstractBootstrop的以下方法

 
   
   
 
  1. final ChannelFuture initAndRegister() {

  2. this.group().register(channel);(中间省略)

  3. }

这个this.group就是一开始设置的bossgroup(NioEventLoopGroup),看到这个方法基本可以想到这个应该是把channel注册到某个选择器上

MultithreadEventLoopGroup

 
   
   
 
  1. public ChannelFuture register(Channel channel) {

  2. return this.next().register(channel);

  3. }

上面的类图已经可以看出 NioEventLoopGroup继承自 MultithreadEventLoopGroup,最终 this.next()又会返回 NioEventLoop,所以也就是可以理解是把 channel注册到 NioEventLoop上(我们猜想 NioEventLoop可以想象成封装了一个 selector

this.next()返回 NioEventLoop继承于 SingleThreadEventLoopchannel.unsafe().register(this,promise);最终调用到 AbstractUnsaferegister方法

 
   
   
 
  1. eventLoop.execute(new OneTimeTask() {

  2. public void run() {

  3. AbstractUnsafe.this.register0(promise);

  4. }

  5. });

这里通过 bossgroup启动一个线程

最终调用到

 
   
   
 
  1. protected void doRegister() throws Exception {

  2. boolean selected = false;


  3. while(true) {

  4. try {

  5. this.selectionKey = this.javaChannel().register(this.eventLoop().selector, 0, this);

  6. return;

  7. } catch (CancelledKeyException var3) {

  8. if(selected) {

  9. throw var3;

  10. }


  11. this.eventLoop().selectNow();

  12. selected = true;

  13. }

  14. }

  15. }

监听端口

可以看到第四张截图

 
   
   
 
  1. ChannelFuture regFuture = this.initAndRegister();

  2. if(regFuture.cause() != null) {

  3. return regFuture;

  4. } else if(regFuture.isDone()) {

  5. doBind0(regFuture, channel, localAddress, promise1); return promise1;

  6. } else {

  7. AbstractBootstrap.doBind0(regFuture, channel, localAddress, promise); } }); return promise;

  8. }

可以看到 initAndRegister()这个方法就是上面我们说的注册感兴趣的事件。后面的 elseifelse都有 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