前言
在上一篇文章中我们详细的走了一遍bind()方法的启动流程, channel的初始化和注册, 并在初始化和注册的时候如果是第一次连接的话会执行pipeline.fireChannelActive();方法进行回调, 这次我们就对回调进行一次详细的讲解
从回调开始
前情回顾
重新带大家回顾一下上一篇文章末尾的知识, 我们进入了AbstractChannel类的register0方法, 这个方法是我们的channel调用注册和回调通知的地方
在register0方法中重点关注上图中三个红框的地方:
doRegister():实际注册的方法pipeline.fireChannelRegistered();回调方法pipeline.fireChannelActive();tcp 首次连接时调用, 也是本章的重点
tcp客户端首次连接服务端
我以debug模式启动Netty项目, 并在该方法上打了断点, 等待一会跳过断点, 可以看到控制台选中部分的时间和上一条打印日志时间间隔近30秒, 在放开debug之后执行了该方法, 调用回调打印
十二月 07, 2022 10:38:37 上午 io.netty.handler.logging.LoggingHandler channelActive 复制代码
剖析pipeline.fireChannelActive方法
一路
Ctrl+左键查看方法详情, 下面注意一下图上的标记类名.方法名
DefaultChannelPipeline.fireChannelActive
AbstractChannelHandlerContext.invokeChannelActive
在该方法中, 我们可以看到不论最后执行结果是什么都会执行一个方法next.invokeChannelActive();, 那我们就进入这个方法看一下
AbstractChannelHandlerContext.invokeChannelActive
最后可以看到不论怎么执行他都会执行到channelActive()方法
- 这个方法继承于
ChannelInboundHandlerAdapter类 ChannelInboundHandlerAdapter类中的channelActive()方法又继承于ChannelInboundHandler接口- 同时, 我们最开始
DefaultChannelPipeline类下面还写了一个内部类HeadContext - 在
HeadContext类中继承了ChannelInboundHandler也实现了该方法, 咱就说隐藏的真深, 我找半天...如下图
HeadContext类和channelActive()方法详情网络异常,图片无法展示|
这个类的继承图如下所示网络异常,图片无法展示|网络异常,图片无法展示|
所以回调到这里就差不多了, 别问我最后怎么理清的, debug大法好, 可能稍微有点乱, 大家最好自己debug走一遍, 再挨个类点开看一下
回调详情
DefaultChannelPipeline
**channel.read();**方法是Channel类的, 因为调用的channel是NioServerSocketChannel, 所以我们直接去他的父类AbstractChannel中查看
NioServerSocketChannel 类的继承图
网络异常,图片无法展示|
从AbstractChannel的read()方法进入到DefaultChannelPipeline的read()方法
这样我们就找到了真正的read()方法, 到这里我们继续分析
findContextOutbound()
顾名思义, 这个方法是查找出栈的
这个方法详情流程如下:
- 先是获取当前
ChannelHandler - 获取当前
ChannelHandler的executor - 获取前一个
ChannelHandler - 判断执行while内的
skipContext方法 skipContext方法的作用: 判断前一个ChannelHandler是否具有响应Write事件的资格
executor.inEventLoop()方法
判断当前线程是不是在当前的EventLoop中对应的那个线程
next.invokeRead()
直接进入这个方法查看一下, 神秘的面纱即将揭晓
有没有很熟悉的感觉, 在剖析pipeline.fireChannelActive方法的时候我们就碰到过类似的方法, 那个是invokeChannelActive()方法, 也是一个回调
因为handler == headContext, 所以最后就是调用的 handler.read()方法
回调执行结果
网络异常,图片无法展示|
发现 doBeginRead() 方法
这里注意一下, 看到this.selectionKey了吗, 如果看我上一篇文章的小伙伴肯定会发现, 这不就是我们之前设置过得值吗
这一步就是重新为我们的selectionKey进行设置
结尾
本来想完成一下任务三的, 但是实在是搞不动了, 下一篇再说吧...