扫描下方二维码或者微信搜索公众号
菜鸟飞呀飞
,即可关注微信公众号,阅读更多Spring源码分析
和Java并发编程
文章。
问题
老规矩,Netty的源码很难、很复杂,为了更快的学懂新的知识,所以还是带着问题来学习源码。
Netty作为一款基于事件驱动的高性能网络框架,其底层实际上仍然使用的是JDK里面的NIO,Netty在JDK的NIO上做了大量优化,以及封装,降低了开发人员使用NIO的难度。
使用JDK原生的NIO进行网络编程时,首先得做两件事:1. 创建以及初始化ServerSocketChannel,2. 将ServerSocketChannel绑定到多路复用器Selector上。既然说Netty对JDK的NIO做了封装,那么在Netty中是什么时候进行这两步操作的呢?(在Netty中服务端的Channel是NioServerSocketChannel)
答案显然就是:在Netty服务端启动的时候进行的。本文接下来就结合源码来看看Netty是如何进行服务端Channel的初始化,关于绑定到Selector的源码分析会发布在下一篇文章中。
组件说明
在看Netty服务端启动流程的源码之前,先来简单介绍下Netty中相关的组件。这些组件很重要,后面会单独针对每一个组件写文章进行详细说明,今天只是先简单介绍一下。
首先是NioEventLoopGroup,看英文名,翻译过来就是一个NIO事件轮询组。可以简单理解为它是一个线程组,它里面包含了一组线程,这些线程后续用来执行客户端的接入、IO数据读写等任务。
NioEventLoop,可以简单理解为它是一个线程,多个NioEventLoop合起来就是一个NioEventLoopGroup。
Pipeline,它是由ChannelHandlerContext类型的元素组成的一个双向链表,ChannelHandlerContext里面包装了一个ChannelHandler。对于服务端而言,每当有新连接接入时,都会通过Pipeline来传播。这个组件十分重要,在实际工作中,使用Netty实现自己自定义的业务逻辑,就是通过修改Pipeline来实现的。
服务端启动
先来看一段服务端启动的demo代码。
在示例代码中,①~⑤都是为Netty服务端设置一些属性,比较简单。需要额外说明的是第②步。在第②步中,对服务端而言,需要设置channel的类型为NioServerSocketChannel。当调用channle(NioServerSocketChannel.class)方法时,会调用到AbstractBootstrap类的channel()方法,它干的事情就是创建一个一个ReflectiveChannelFactory工厂,并将ReflectiveChannelFactory实例赋值给AbstractBootstrap类的channelFactory属性。
对于ReflectiveChannelFactory而言,它有一个Constructor类型的属性,叫做constructor,它就是后续用来创建Channel的反射构造器。对于此处而言,constructor就是NioServerSocketChannel.class的反射构造器,通过它就能创建出一个NioServerSocketChannel的实例对象。
channel()方法的源码
ReflectiveChannelFactory构造器的源码
在第⑥步中,会调用ServerBootstrap的bind()方法,这个方法中传入了一个端口号:8080。从外面看,这个方法及其简单,但是它干的事情非常多。在这个方法中会初始化服务端的channel,注册channel到selector上,然后绑定端口,启动服务端。下面来通过分析它的源码,来看下服务端Channel是如何进行初始化和绑定操作的。
当调用ServerBootstrap.bind(8080)时,会调用到ServerBootstrap.doBind(),下面我简化了一下doBind()方法的源码,只保留了核心代码,如下。
在doBind()方法中调用了两个非常重要的方法,一个是initAndRegister()方法,它用来进行Channel的初始化和注册到Selector上的操作;另外一个是doBind0()方法,它用来进行端口号的绑定操作。今天只分析initAndRegister()方法的前半部分。
channel初始化
initAndRegister()的源码如下。
在initAndRegister()方法中,会先通过调用channelFactory.newChannel()来创建一个Channle,对于服务端而言,这里创建的就是NioServerSocketChannel。那么它是如何创建的呢?
首先这里的channelFactory就是前面在②处提到的ReflectiveChannelFactory,它里面包含一个属性constructor。这个constructor就是NioServerSocketChannel.class
的反射构造器,通过调用constructor.newInstance()
方法,就会调用到NioServerSocketChannel类的无参构造方法。NioServerSocketChannel的无参构造方法如下。
public NioServerSocketChannel() {
// DEFAULT_SELECTOR_PROVIDER的值就是SelectorProvider.provider()
// 先调用newSocket()
this(newSocket(DEFAULT_SELECTOR_PROVIDER));
}
在无参构造方法中会先调用newSocket()方法,该方法就是通过JDK原生的API创建一个ServerSocketChannel。
private static ServerSocketChannel newSocket(SelectorProvider provider) {
try {
// provider的值就是SelectorProvider.provider();
// 这里就是直接调用JDK中NIO的原生API,创建ServerSocketChannel
return provider.openServerSocketChannel(