概述
写此篇文章难度还是比较大的,对于一个初出茅庐的我来说理解 Netty 整体架构都有一定难度,更别说把它写成一篇文章。不过呢,只有实际下笔写才能让自己对 Netty 的整体架构有更深刻的认识。
从这篇文章开始,我们就踏上 Netty 源码的路程,虽然几近坎坷,但是当你完成 Netty 源码这段奇妙的旅程后回首一看,发现自己早已长大成人。
Netty 的源码我会基于最新的版本 Netty-4.1.58.Final 为基准进行解读。在讲解源码之前,我们先对 Netty 的整体架构及相关组件进行概述。
Netty 整体架构
说到 Netty 整体架构,不得不放出 Netty 官网最醒目的图片:
从图中,可以清晰看出 Netty 总共分成三大模块:
- Core 核心层:是 Netty 最精华的内容,它提供了对底层网络通信的封装和抽象。
- Transport Service 传输服务层:传输服务层提供了网络传输能力的定义和实现方法。支持 Socket、HTTP 隧道、虚拟机管道等传输方式。使得用户可以专注于具体的业务逻辑,而不必关心底层数据传输细节。
- Protocol Support 协议支持层:基本覆盖了主流协议的编解码实现,如 HTTP、SSL、Google Protobuf、WebSocket 等等,拿来即用,而且 Netty 提供丰富的扩展接口,用户可快速实现个性化需求 。
Netty 的设计符合高内聚、低耦合的设计理念,具备了很高的接口通用性和可扩展能力。
Netty 核心组件
这些组件代表了不同类型的模块:资源、逻辑以及通知。你的应用程序将会使用它们来访问网络以及流经网络的数据。
Channel
Channel 是 Java NIO 的一个最核心也是最基础的组件。
Channel 代表一个到实体(如一个硬件设备、一个文件、一个网络套接字或者一个能够执行一个或多个不同的 I/O 操作的程序组件)的开放连接,如读操作和写操作。
目前,可以把 Channel 看作是入站和出站的数据的载体。因此,它可以被打开或被关闭、连接或断开连接。
回调
一个回调其实就是一个方法,一个指向已经被提供给另外一个方法的方法引用。这使得后者可以在适当的时候调用前者。Netty 在内部使用了回调来处理事件:当一个回调被触发时,想在的事件可以被一个 ChannelHandler 的实现处理。
Future
Future 提供了另一种在操作完成时通知应用程序的方式。这个对象可以看作是一个异步操作的结果的占位符;它将在未来的某个时刻完成,并提供对其结果的访问。
JDK 预置了 java.util.concurrent.Future
,但是其所提供的实现,只允许手动检查对应的操作是否已经完成,或者一直阻塞直到它完成。这是非常繁琐的,所以 Netty 提供了它自己的实现——ChannelFuture
,用于在执行异步操作的时候使用。ChannelFuture
提供了几种额外的方法,这些方法使得我们能够注册一个或者多个 ChannelFutureListener 实例。监听器的回调方法 operationComplete()
,将会在对应的操作完成时被调用。然后监听器可以判断该操作是成功地完成了还是出错了。如果是后者,我们可以检索产生的 Throwable。简而言之 ,由 ChannelFutureListener 提供的通知机制消除了手动检查对应的操作是否完成的必要。
每个 Netty 的出站 I/O 操作都将返回一个 ChannelFuture;也就是说,它们都不会阻塞。正如我们前面所提到过的一样,Netty 完全是异步和事件驱动的。
事件和 ChannelHandler
Netty 使用不同的事件来通知我们状态的改变或者是操作的状态。这使得我们能够基于已经 发生的事件来触发适当的动作。
Netty 的 ChannelHandler 提供了处理器的基本抽象。而且内置了大量的开箱即用的 ChannelHandler 实例。
Netty 整体执行逻辑
下图是 Netty 整体执行逻辑。很明显看出是它是采用主从 Reactor 模型,你也可以轻松通过配置 ServerBootstrap 变成单 Reactor 多线程模型。但在实际的开发中,通常采用主从 Reactor 模型以达到最高并发。
客户端通过 Boss NioEventGroup 连接并创建相关 Channel,Boss NioEventGroup 只会有一个线程处理所有 I/O 连接事件,当一个连接完成 TCP 三次握手后,表明连接建立成功,随后 Boss NioEventLoop 向 Worker NioEventGroup 注册刚建立连接的通道,Worker 会从线程组中轮询得到一个 NioEventLoop 对象和 Channel 绑定,后续 Channel 的生命周期以及相关事件处理都只由这个 NioEventLoop 完成。上图的最后是 ChannelPipeline,这也是 Netty 提供的最重要的扩展点,用户在这里添加自定义逻辑,同时,Netty 也提供了开箱即用的 ChannelHandler,比如解决”拆包/粘包” 的 FixedLengthFrameDecoder、LineBasedFrameDecoder 和 DelimiterBasedFrameDecoder。
Netty 对底层的接口抽象做得十分到位,比如除了使用 Java NIO 技术,对 Linux 服务器而言,还有更高效的 EPOLL,Netty 也提供了相应的 EpollEventLoop,但你只需要修改一个地方就可以完成配置。