Netty 的核心组件

Netty 的核心组件_第1张图片

Netty 的核心组件有哪些?

1. Bootstrap 与 ServerBootstrap

Bootstrap 与 ServerBootstrap 是 Netty 程序的引导类,主要用于配置各种参数,并启动整个 Netty 服务。它们俩都继承自 AbstractBootstrap 抽象类,不同的是, Bootstrap 用于客户端引导,而 ServerBootstrap 用于服务端引导。Netty 的核心组件_第2张图片
相对于 Bootstrap , ServerBootstrap 多了一个维度,用于处理 Accept 事件,所以它的很多方法都会多一份 childXxx() ,比如, childHandler() 、 childOption() 等,但是,没有 childChannel() 这个方法哦 ^^ ,因为子 Channel 是通过ServerSocketChannel 创建出来的,跟踪源码会发现 ServerSocketChannel 读取到消息的时候会把这个消息转换成连接,即 SocketChannel 。

EventLoopGroup

EventLoopGroup 可以理解为一个线程池,对于服务端程序,我们一般会绑定两个线程池,一个用于处理 Accept事件,一个用于处理读写事件。
我们以 NioEventLoopGroup 这个实现类为例看看它的继承体系、
Netty 的核心组件_第3张图片
上面四个接口好熟悉:
Iterable ,迭代器的接口,说穿 EventLoopGroup 是一个容器,可以通过迭代的方式查看里面的元素。
Executor ,线程池的顶级接口,包含一个 execute () 方法,用于提交任务到线程池中。
ExecutorService ,扩展自 Executor 接口,提供了通过 submit () 方法提交任务的方式,并增加了 shutdown ()等其它方法。
ScheduledExecutorService ,扩展自 ExecutorService ,增加了定时任务执行相关的方法。
其中,后面三个都是线程池中的接口,位于著名的 java.util.concurrent 包下面
下面的几个接口或者类自然就属于 Netty 了:
EventExecutorGroup ,扩展自 ScheduledExecutorService ,并增加了两大功能,一是提供了 next () 方法用于获取一个 EventExecutor ,二是管理这些 EventExecutor 的生命周期。
EventLoopGroup ,扩展自 EventExecutorGroup ,并增加或修改了两大功能,一是提供了 next () 方法用于获取一个 EventLoop ,二是提供了注册 Channel 到事件轮询器中。
MultithreadEventLoopGroup ,抽象类, EventLoopGroup 的所有实现类都继承自这个类,可以看作是一种模板,从名字也可以看出来它里面包含多个线程来处理任务。

NioEventLoopGroup ,具体实现类,使用 NIO 形式(多路复用中的 select )工作的 EventLoopGroup 。更换前缀就可以得到不同的实现类,
比如 EpollEventLoopGroup 专门用于 Linux 平台,
KQueueEventLoopGroup 专门用于 MacOS/BSD 平台。
select/epoll/kqueue ,它们是实现 IO 多路复用的不同形式,
select 支持的平台比较广泛, epoll 和 kqueue比 select 更高效,
epoll 只支持 linux ,kqueue 只支持 BSD 平台,其中 MacOS 衍生自 BSD ,所以kqueue 也支持 MacOS 。 Netty 专门为两个平台做了的不同实现,也是对性能的极致追求,而且,我们服务端通常都是运行在 Linux 系统上,所以在上线的时候完全可以使用 EpollEventLoopGroup 来代替NioEventLoopGroup 。
记住一点:
有的同学可能会说,为什么 Netty 要把继承体系搞这么复杂,这么深呢?其实,通过上面的分析也可以得出一些蛛丝马迹,每一个接口都是在上一层接口的基础上扩展一些新的功能,属于每一个接口自己的功能都特别纯粹,并不是很多,这也是单一职责原则的具体使用,使用多个单一的接口比使用一个总接口要好。

3. EventLoop

EventLoop 可以理解为是 EventLoopGroup 中的工作线程,类似于 ThreadPoolExecutor 中的 Worker ,但是,实际
上,它并不是一个线程,它里面包含了一个线程,控制着这个线程的生命周期。

Netty 的核心组件_第4张图片

4. ByteBuf 此处不做展开

5. Channel

Channel 是 Netty 在 Java NIO 的 Buffer 之上创造的一个新的缓冲区,比 Java 自带的语义清晰很多,也好用很多。

那么, Channel 是不是也是凌驾于 Java NIO 的 Channel 之上的一个新事物呢?
答案是肯定的, Netty 的 Channel 是对 Java 原生 Channel 的进一步封装,不仅封装了原生 Channel 操作的复杂性,还提供了一些很酷且实用的功能,比如:

  1. 可以获取当前连接的状态及配置参数
  2. 通过 ChannelPipeline 来处理 IO 事件
  3. 在 Netty 中的所有 IO 操作都是异步的
  4. 可继承的 Channel 体系

6. ChannelHandler

ChannelHandler 是核心业务处理接口,用于处理或拦截 IO 事件,并将其转发到 ChannelPipeline 中的下一个ChannelHandler ,运用的是责任链设计模式。

责任链设计模式 责任链模式

ChannelHandler 分为入站和出站两种:
ChannelInboundHandler 和 ChannelOutboundHandler ,
不过一般不建议直接实现这两个接口,而是它们的抽象类:
1 SimpleChannelInboundHandler :处理入站事件,不建议直接使用 ChannelInboundHandlerAdapter
2 ChannelOutboundHandlerAdapter :处理出站事件
ChannelDuplexHandler :双向的
其中, SimpleChannelInboundHandler 相比于 ChannelInboundHandlerAdapter 优势更明显,它可以帮我们做资源的自动释放等操作。

7. ChannelHandlerContext

ChannelHandlerContext 保存着 Channel 的上下文,同时关联着一个 ChannelHandler ,通过ChannelHandlerContext , ChannelHandler 方能与 ChannelPipeline 或者其它 ChannelHandler 进行交互, ChannelHandlerContext 是它们之间的纽带。

8. ChannelFuture

我们上面说了 Netty 中所有的 IO 操作都是异步的,既然是异步的就会返回在将来用来获取返回值的对象,也就是Future ,在 Netty 中,这个 Future 我们称之为 ChannelFuture ,因为是跟 Channel 的 IO 事件相关联的,当然, Netty 中还有其它各种各样的 Future 。通过 ChannelFuture ,可以查看 IO 操作是否已完成、是否成功、是否已取消等等

9. ChannelPipeline

ChannelPipeline 是 ChannelHandler 的集合,它负责处理和拦截入站和出站的事件和操作,每个 Channel 都有一个ChannelPipeline 与之对应,会自动创建。
更确切地说, ChannelPipeline 中存储的是 ChannelHandlerContext 链,通过这个链把 ChannelHandler 连接起来,让我们仔细研究一下几者之间的关系:

一个 Channel 对应一个 ChannelPipeline
一个 ChannelPipeline 包含一条双向的 ChannelHandlerContext 链.
一个 ChannelHandlerContext 中包含一个 ChannelHandler.
一个 Channel 会绑定到一个 EventLoop 上.
一个 NioEventLoop 维护了一个 Selector (使用的是 Java 原生的 Selector )
一个 NioEventLoop 相当于一个线程.

通过以上分析,可以得出, ChannelPipeline 、 ChannelHandlerContext 都是线程安全的,因为同一个 Channel 的事件都会在一个线程中处理完毕(假设用户不自己启动线程)。但是, ChannelHandler 却不一定, ChannelHandler 类似于 Spring MVC 中的 Service 层,专门处理业务逻辑的地方,一个 ChannelHandler 实例可以供多个 Channel 使用,所以,不建议把有状态的变量放在 ChannelHandler 中,而是放在消息本身或者 ChannelHandlerContext 中。

TODO 为什么 不建议把有状态的变量放在 ChannelHandler ???等等等有空添加个源码来看看,待续

问题:ChannelHandler 是否是线程安全呢?为什么?
Netty 的核心组件_第5张图片
动手论证:问题:ChannelHandler 是否是线程安全呢?为什么?

你可能感兴趣的:(Netty源码剖析,java,python,测试工具)