从 Spring Boot 程序启动深入理解 Netty 异步架构原理( 三 )


③ChannelHandler,ChannelPipeline 和 ChannelHandlerContext
如果说 EventLoop 是事件的通知者,那么 ChannelHandler 就是事件的处理者 。
在 ChannelHandler 中可以添加一些业务代码,例如数据转换,逻辑运算等等 。
正如上面例子中展示的,Server 和 Client 分别都有一个 ChannelHandler 来处理,读取信息,网络可用,网络异常之类的信息 。
并且,针对出站和入站的事件,有不同的 ChannelHandler,分别是:

  • ChannelInBoundHandler(入站事件处理器)
  • ChannelOutBoundHandler(出站事件处理器)

从 Spring Boot 程序启动深入理解 Netty 异步架构原理

文章插图
 
假设每次请求都会触发事件,而由 ChannelHandler 来处理这些事件,这个事件的处理顺序是由 ChannelPipeline 来决定的 。
从 Spring Boot 程序启动深入理解 Netty 异步架构原理

文章插图
ChannelHanlder 处理,出站/入站的事件
ChannelPipeline 为 ChannelHandler 链提供了容器 。到 Channel 被创建的时候,会被 Netty 框架自动分配到 ChannelPipeline 上 。
ChannelPipeline 保证 ChannelHandler 按照一定顺序处理事件,当事件触发以后,会将数据通过 ChannelPipeline 按照一定的顺序通过 ChannelHandler 。
说白了,ChannelPipeline 是负责“排队”的 。这里的“排队”是处理事件的顺序 。
同时,ChannelPipeline 也可以添加或者删除 ChannelHandler,管理整个队列 。
从 Spring Boot 程序启动深入理解 Netty 异步架构原理

文章插图
 
如上图,ChannelPipeline 使 ChannelHandler 按照先后顺序排列,信息按照箭头所示方向流动并且被 ChannelHandler 处理 。
说完了 ChannelPipeline 和 ChannelHandler,前者管理后者的排列顺序 。那么它们之间的关联就由 ChannelHandlerContext 来表示了 。
每当有 ChannelHandler 添加到 ChannelPipeline 时,同时会创建 ChannelHandlerContext。
ChannelHandlerContext 的主要功能是管理 ChannelHandler 和 ChannelPipeline 的交互 。
不知道大家注意到没有,开始的例子中 ChannelHandler 中处理事件函数,传入的参数就是 ChannelHandlerContext 。
从 Spring Boot 程序启动深入理解 Netty 异步架构原理

文章插图
 
ChannelHandlerContext 参数贯穿 ChannelPipeline,将信息传递给每个 ChannelHandler,是个合格的“通讯员” 。
从 Spring Boot 程序启动深入理解 Netty 异步架构原理

文章插图
ChannelHandlerContext 负责传递消息
把上面提到的几个核心组件归纳一下,用下图表示方便记忆他们之间的关系 。
从 Spring Boot 程序启动深入理解 Netty 异步架构原理

文章插图
Netty 核心组件关系图
Netty 的数据容器前面介绍了 Netty 的几个核心组件,服务器在数据传输的时候,产生事件,并且对事件进行监控和处理 。
接下来看看数据是如何存放以及是如何读写的 。Netty 将 ByteBuf 作为数据容器,来存放数据 。
ByteBuf 工作原理
从结构上来说,ByteBuf 由一串字节数组构成 。数组中每个字节用来存放信息 。
ByteBuf 提供了两个索引,一个用于读取数据,一个用于写入数据 。这两个索引通过在字节数组中移动,来定位需要读或者写信息的位置 。
当从 ByteBuf 读取,它的 readerIndex(读索引)将会根据读取的字节数递增 。
同样,当写 ByteBuf 时,它的 writerIndex 也会根据写入的字节数进行递增 。
从 Spring Boot 程序启动深入理解 Netty 异步架构原理

文章插图
ByteBuf 读写索引图例
需要注意的是极限的情况是 readerIndex 刚好读到了 writerIndex 写入的地方 。
如果 readerIndex 超过了 writerIndex 的时候,Netty 会抛出 IndexOutOf-BoundsException 异常 。
ByteBuf 使用模式
谈了 ByteBuf 的工作原理以后,再来看看它的使用模式 。
根据存放缓冲区的不同分为三类: