深入浅出Netty:服务启动

本系列:

《深入浅出Netty(1)》


本节主要分析server的启动过程。

Netty是基于Nio实现的,所以也离不开selector、serverSocketChannel、socketChannel和selectKey等,只不过Netty把这些实现都封装在了底层。

从示例可以看出,一切从ServerBootstrap开始。

ServerBootstrap实例中需要两个NioEventLoopGroup实例,分别为boss和work,有不同的分工:
1、 boss负责请求的accept操作。
2、 work负责请求的read、write和处理操作。

NioEventLoopGroup

NioEventLoopGroup主要负责管理eventLoop的生命周期,eventLoop数量默认为处理器个数的两倍。


NioEventLoopGroup

继承关系如下:


NioEventLoopGroup

NioEventLoopGroup构造方法:

MultithreadEventLoopGroup构造方法:

其中 DEFAULT_EVENT_LOOP_THREADS 为处理器数量的两倍。

MultithreadEventExecutorGroup是核心,管理eventLoop的生命周期,先看看其中几个变量。
1、children:EventExecutor数组,保存eventLoop。
2、chooser:从children中选取一个eventLoop的策略。

构造方法:

1、 根据数组的大小,采用不同策略初始化chooser。
如果大小为2的幂次方,则采用PowerOfTwoEventExecutorChooser;否则使用GenericEventExecutorChooser。
判断一个数是否是2的幂次方的方法,觉得很赞。

2、newChild方法重载,初始化EventExecutor时,实际执行的是NioEventLoopGroup中的newChild方法,所以,children元素的实际类型为NioEventLoop。


接下去看看NioEventLoop类。

NioEventLoop

每个eventLoop会维护一个selector和taskQueue,负责处理客户端请求和内部任务,如ServerSocketChannel注册和ServerSocket绑定等。


NioEventLoop

继承关系如下:


NioEventLoop

构造方法:

当看到 selector = openSelector() 时,有没有觉得亲切了许多,这里先不管 selector,看看SingleThreadEventLoop类。

SingleThreadEventLoop 构造方法:

啥事都没做…


SingleThreadEventExecutor
从命名上可以看出,这是一个只有一个线程的线程池, 先看看其中的几个变量:
1、state:线程池当前的状态
2、taskQueue:存放任务的队列
3、thread:线程池维护的唯一线程
4、scheduledTaskQueue:定义在其父类AbstractScheduledEventExecutor中,用以保存延迟执行的任务。

构造方法:

代码很长,内容很简单:
1、初始化一个线程,并在线程内部执行NioEventLoop类的run方法,当然这个线程不会立刻执行。
2、使用LinkedBlockingQueue类初始化taskQueue。

ServerBootstrap

通过serverBootstrap.bind(port)启动服务,过程如下:


bind过程

doBind实现如下

1、方法initAndRegister返回一个ChannelFuture实例regFuture,通过regFuture可以判断initAndRegister执行结果。
2、如果regFuture.isDone()为true,说明initAndRegister已经执行完,则直接执行doBind0进行socket绑定。
3、否则regFuture添加一个ChannelFutureListener监听,当initAndRegister执行完成时,调用operationComplete方法并执行doBind0进行socket绑定。

所以只有当initAndRegister操作结束之后才能进行bind操作。

initAndRegister

1、主要负责创建服务端channel,在本例子中,创建了NioServerSocketChannel。
2、为NioServerSocketChannel的pipeline添加handler。
3、注册NioServerSocketChannel到selector。

NioServerSocketChannel

对Nio的ServerSocketChannel和SelectionKey进行了封装。

继承关系:


NioServerSocketChannel继承关系

构造方法:

1、方法newSocket利用 provider.openServerSocketChannel() 生成Nio中的ServerSocketChannel对象。
2、设置SelectionKey.OP_ACCEPT事件。

AbstractNioMessageChannel构造方法

啥也没做…

AbstractNioChannel构造方法

设置当前ServerSocketChannel为非阻塞通道。

AbstractChannel构造方法

1、初始化unsafe。
这里的Unsafe并非是jdk中底层Unsafe类,用来负责底层的connect、register、read和write等操作。

2、初始化pipeline。
每个Channel都有自己的pipeline,当有请求事件发生时,pipeline负责调用相应的hander进行处理。

unsafe和pipeline的具体实现原理会在后续进行分析。


回到ServerBootstrap的init(Channel channel)方法,添加handler到channel的pipeline中。

1、设置channel的options和attrs。
2、在pipeline中添加一个ChannelInitializer对象,每个client请求进来都会执行initChannel方法。


init执行完,需要把当前channel注册到EventLoopGroup。

其实最终目的是为了实现Nio中把ServerSocket注册到selector上,这样就可以实现client请求的监听了。

看看Netty中是如何实现的:

因为EventLoopGroup中维护了多个eventLoop,next方法会调用chooser策略找到下一个eventLoop,并执行eventLoop的register方法进行注册。

channel.unsafe()是什么?
NioServerSocketChannel初始化时,会创建一个NioMessageUnsafe实例,用于实现底层的register、read、write等操作。

1、register0方法提交到eventLoop线程池中执行,这个时候会启动eventLoop中的线程。
2、方法doRegister()才是最终Nio中的注册方法,方法javaChannel()获取ServerSocketChannel。

ServerSocketChannel注册完之后,通知pipeline执行fireChannelRegistered方法,pipeline中维护了handler链表,通过遍历链表,执行InBound类型handler的channelRegistered方法,最终执行init中添加的ChannelInitializer handler。

1、initChannel方法最终把ServerBootstrapAcceptor添加到ServerSocketChannel的pipeline,负责accept客户端请求。
2、在pipeline中删除对应的handler。
3、触发fireChannelRegistered方法,可以自定义handler的channelRegistered方法。

到目前为止,ServerSocketChannel完成了初始化并注册到seletor上,启动线程执行selector.select()方法准备接受客户端请求。

细心的同学已经发现,ServerSocketChannel的socket还未绑定到指定端口,那么这一块Netty是如何实现的?
Netty把注册操作放到eventLoop中执行。

最终由unsafe实现端口的bind操作。

bind完成后,且ServerSocketChannel也已经注册完成,则触发pipeline的fireChannelActive方法,所以在这里可以自定义fireChannelActive方法,默认执行tail的fireChannelActive。

channel.read()方法会触发pipeline的行为:

最终会在pipeline中找到handler执行read方法,默认是head。

至此为止,server已经启动完成。

END。

打赏支持我写出更多好文章,谢谢!

打赏作者

打赏支持我写出更多好文章,谢谢!

1 收藏 评论

关于作者:占小狼

我是占小狼。在魔都艰苦奋斗,白天是上班族,晚上是知识服务工作者。如果读完觉得有收获的话,记得关注和点赞哦。非要打赏的话,我也是不会拒绝的。 个人主页 · 我的文章 · 11 ·  

相关文章

可能感兴趣的话题



直接登录
跳到底部
返回顶部