我是靠谱客的博主 诚心黄豆,最近开发中收集的这篇文章主要介绍Java NIO框架Netty教程(四) – ServerBootStrap启动流程源码分析,觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
花了几天时间,仔细梳理了一下Netty的源码,总结了一下ServerBootStrap的启动和任务处理流程,基本涵盖了Netty的关键架构。
OneCoder总结了一张流程图:
该图是
OneCoder通过阅读Netty源码,逐渐记录下来的。基本可以说明Netty服务的启动流程。这里在具体讲解一下。
首先说明,我们这次顺利的流程是基于NioSocketServer的。也就是基于Java NIO Selector的实现方式。在第六讲
《Java NIO框架Netty教程(六)-Java NIO Selector模式》中,我们已经知道使用Selector的几个关键点,所以这里我们也重点关注一下,这些点在Netty中是如何使用的。
很多看过Netty源码的人都说Netty源码写的很漂亮。可漂亮在哪呢?Netty通过一个ChannelFactory决定了你当前使用的协议类型 (Nio/oio等),比如,OneCoder这里使用的是NioServerSocket,那么需要声明的Factory即为 NioServerSocketChannelFactory,声明了这个Factory,就决定了你使用的Channel,pipeline以及 pipeline中,具体处理业务的sink的类型。这种使用方式十分简洁的,学习曲线很低,切换实现十分容易。
Netty采用的是基于事件的管道式架构设计,事件(Event)在管道(Pipeline)中流转,交由(通过pipelinesink)相应的处理器(Handler)。这些关键元素类型的匹配都是由开始声明的ChannelFactory决定的。
Netty框架内部的业务也遵循这个流程,Server端绑定端口的binder其实也是一个Handler,在构造完Binder后,便要声明一个 Pipeline管道,并赋给新建一个Channel。Netty在newChannel的过程中,相应调用了Java中的 ServerSocketChannel.open方法,打开一个channel。然后触发fireChannelOpen事件。这个事件的接受是可以复写的。Binder自身接收了这个事件。在事件的处理中,继续向下完成具体的端口的绑定。对应Selector中的 socketChannel.socket().bind()。然后触发fireChannelBound事件。默认情况下,该事件无人接受,继续向下开始构造Boss线程池。我们知道在Netty中Boss线程池是用来接受和分发请求的核心线程池。所以在channel绑定后,必然要启动Boss线城池,随时准备接受client发来的请求。在Boss构造函数中,第一次注册了selector感兴趣的事件类型,SelectionKey.OP_ACCEPT。至此,在第六讲中介绍的使用Selector的几个关键步骤都体现在Netty中了。在Boss中回启动一个死循环来查询是否有感兴趣的事件发生,对于第一次的客户端的注册事件,Boss会将Channel注册给worker保存。
这里补充一下,也是图中忽略的部分,就是关于worker线程池的初始化时机问题。worker池的构造,在最开始构造ChannelFactory的时候就已经准备好了。在NioServerSocketChannelFactory的构造函数里,会new一个NioWorkerPool。在 NioWorkerPool的基类AbstractNioWorkerPool的构造函数中,会调用OpenSelector方法,其中也打开了一个 selector,并且启动了worker线程池。
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
private
void
openSelector() {
try
{
selector = Selector.open();
}
catch
(Throwable t) {
throw
new
ChannelException(
"Failed to create a selector."
, t);
}
// Start the worker thread with the new Selector.
boolean
success =
false
;
try
{
DeadLockProofWorker.start(executor,
new
ThreadRenamingRunnable(
this
,
"New I/O worker #"
+ id));
success =
true
;
}
finally
{
if
(!success) {
// Release the Selector if the execution fails.
try
{
selector.close();
}
catch
(Throwable t) {
logger.warn(
"Failed to close a selector."
, t);
}
selector =
null
;
// The method will return to the caller at this point.
}
}
assert
selector !=
null
&& selector.isOpen();
}
|
至此,会分线程启动AbstractNioWorker中run逻辑。同样是循环处理任务队列。
1
2
3
4
|
processRegisterTaskQueue();
processEventQueue();
processWriteTaskQueue();
processSelectedKeys(selector.selectedKeys());
|
这样,设计使事件的接收和处理模块完全解耦。
由此可见,如果你想从nio切换到oio,只需要构造不同的ChannelFacotry即可。果然简洁优雅。
最后
以上就是诚心黄豆为你收集整理的Java NIO框架Netty教程(四) – ServerBootStrap启动流程源码分析的全部内容,希望文章能够帮你解决Java NIO框架Netty教程(四) – ServerBootStrap启动流程源码分析所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复