前言
一直大大咧咧, 有点健忘, 万万没想到, 这次写文章也健忘了, 之前我们分析Netty
的启动流程讲了初始化和注册, 但是初始化和注册成功之后的doBind0()
方法给忘的一干二净...
浅浅回顾一下:
- 在
Netty
自定义启动类MyServer
中执行了ServerBootstrap.bind(port).sync()
方法启动Netty
- 在
bind()
方法的具体实现doBind()
方法中先是执行了initAndRegister()
方法, 对channel
进行了初始化和注册 - 当初始化和注册完成之后就会执行到
doBind0()
方法
doBind0()方法
在这个方法中, 我们可以看到, 他就是channle.eventLoop()
执行了一个Runnable
channle.eventLoop() 方法
channle.eventLoop()
方法是一个多态, 执行的是AbstractChannel
类下的方法, 在这个方法中可以看到, 他就是对eventLoop
进行了赋值并返回, 至于这个this.eventLoop
的初始化是在register
的时候
Netty服务端启动流程分析 - 掘金 (juejin.cn)
网络异常,图片无法展示|
// 简单代码如下 @Override public final void register(EventLoop eventLoop, final ChannelPromise promise) { .... AbstractChannel.this.eventLoop = eventLoop; ... } 复制代码
通过我们打断点可以发现eventLoop
的类型是NioEventLoop
, 继承关系图如下所示
通过断点我们可以看到具体的执行过程就是进入到execute
方法. 然后判断task
是否为空, 不为空就进入最后的execute
方法
在这个方法内部执行流程:
- 判断当前线程是否为
eventLoop
线程 - 将任务添加到
taskQueue
队列
addTask()
方法详情, offerTask()
方法的作用就是添加任务, 并返回是否添加成功, 如果添加失败, 就拒绝执行处理器
channel.bind()
接下来我们回到doBind0
方法, 继续往下分析
channel
是NioServerSocketChannel
类, 而bind方法的实现类是在AbstractChannel
里面
调用的是pipeline.bind()
,pipeline
它链接了ChannelHandlerContext
,head是outbound,tail是inbound.
继续往下走 ,他会执行tail.bind()
方法, 进入到AbstractChannelHandlerContext
的bind()
方法
如果你看过我上一篇文章, 就会有很熟悉的感觉, findContextOutbound
方法, 我们在上一篇文章有说
执行完findContextOutbound()
方法之后, 也是我们熟悉的一部分, 已经讲过很多次了
next.invokeBind(localAddress, promise);
方法就是执行回调的
端口绑定的发生
再次进入这个方法
pipeline.head
就是outbound
, 所以在这里的时候会执行DefaultChannelPipeline.bind()
方法
再往下走
我们到了AbstractChannel
类的bind
方法, 直接看doBind()
, 打断点跳转
在这里就是执行了 JDK 原生的bind()
方法来绑定端口信息, 至此, 我们的Netty启动系列
终于算是差不多完结了, 吗?
下一篇文章开始继续攻克任务三, 为什么创建的channel
是非阻塞的