Netty 组件深入了解
EventLoop 和 EventLoopGroup
我们在 NIO 中是如何处理我们关心的事件的?在一个 while 循环中 select 出事 件,然后依次处理每种事件。我们可以把它称为事件循环,这就是 EventLoop。EventLoop 定义了 Netty 的核心抽象,用于处理网络连接的生命周期中所发生的事件。
io.netty.util.concurrent 包构建在 JDK 的 java.util.concurrent 包上。而 io.netty.channel 包 中的类,为了与 Channel 的事件进行交互,扩展了这些接口/类。一个 EventLoop 将由一个永远都不会改变的 Thread 驱动,同时任务(Runnable 或者 Callable)可以直接提交给 EventLoop 实现,以立即执行或者调度执行。
线程的分配
见上图关系:一旦一个 Channel 被分配给一个 EventLoop,它将在它的整个生命周期中都使用这个 EventLoop(以及相关联的 Thread)。服务于 Channel 的 I/O 和事件的 EventLoop 包含在 EventLoopGroup 中。
也就是说EventLoop会和一个线程相关联,和EventLoop所绑定的channel会共享一个线程模型,这样设计可以通过尽可能少量的 Thread 来 支撑大量的 Channel,而不是每个 Channel 分配一个 Thread。EventLoopGroup 负责为每个 新创建的 Channel 分配一个 EventLoop。
线程管理
当有任务提交时,会判断当前线程是否是支撑 EventLoop 的线程,那么所提交的任务会被直接执行。否则,EventLoop会将他放入内部队列中。当EventLoop下次处理它的事件时,它会执行队列中的任务。
ChannelPipeline 接口
当 Channel 被创建时,它将会被自动地分配一个新的 ChannelPipeline,每个 Channel 都有自己的 ChannelPipeline。
ChannelPipeline 提供了 ChannelHandler 链的容器,并定义了用于在该链上传播入站(也 就是从网络到业务处理)和 出站(也就是从业务处理到网络),各种事件流的 API,我们 代码中的 ChannelHandler 都是放在 ChannelPipeline 中的。
使得事件流经 ChannelPipeline 是 ChannelHandler 的工作,它们是在应用程序的初始化 或者引导阶段被安装的。这些 ChannelHandler 对象接收事件、执行它们所实现的处理逻辑, 并将数据传递给链中的下一个 ChannelHandler,而且 ChannelHandler 对象也完全可以拦截事件不让事件继续传递。它们的执行顺序是由它们被添加的顺序所决定的。
ChannelHandlerContext
ChannelHandlerContext 代表了 ChannelHandler 和 ChannelPipeline 之间的关联,每当有 ChannelHandler 添加到 ChannelPipeline 中时,都会创建 ChannelHandlerContext,ChannelPipeline 以双向链表的形式进行维护管理 Handler,毫无疑问,Handler 在放入 ChannelPipeline 的时候必须要有两个指针 pre 和 next 来说明它的前一个元素和后一个元素,但是 Handler 本身来维护这两个指针并不合适,想想我们在使用 JDK 的 LinkedList 的时候,我们放入 LinkedList 的数据是不会带这两个指 针的,LinkedList 内部会用类 Node 对我们的数据进行包装,而类 Node 则带有两个指针 pre 和 next。 所以,ChannelHandlerContext 的主要作用就和 LinkedList 内部的类 Node 类似。
ChannelHandler
从应用程序开发人员的角度来看,Netty 的主要组件是 ChannelHandler,它充当了所有处理入站和出站数据的应用程序逻辑的容器。ChannelHandler 的方法是由网络事件触发的。 事实上,ChannelHandler 可专门用于几乎任何类型的动作,例如将数据从一种格式转换为另 外一种格式,例如各种编解码,或者处理转换过程中所抛出的异常。