Netty 基础介绍
Netty 是由 JBoss 开源的一款高性能、异步事件驱动的 NIO 框架,专门用于开发可扩展的网络应用程序(如服务器、客户端)。它基于 Java NIO 封装,解决了原生 NIO 编程复杂、易出错、断连重连/半包处理等痛点,是目前 Java 领域高性能网络编程的事实标准(如 Dubbo、Elasticsearch、RocketMQ 等中间件均基于 Netty 构建)。
一、Netty 核心定位与优势
1. 核心定义
Netty = 「Java NIO 增强版」 + 「异步事件驱动」 + 「高性能网络编程框架」
- 本质:对 Java NIO 的封装和增强,屏蔽原生 NIO 的复杂性(如 Selector 空轮询、半包粘包、线程模型设计等);
- 核心目标:让开发者以极简的代码实现高并发、高可靠的网络通信。
2. Netty 核心优势
| 特性 | 说明 |
|---|---|
| 高性能 | 基于 Reactor 线程模型,支持单线程/多线程 Reactor,吞吐量远超原生 NIO |
| 易用性 | 封装了 NIO 底层细节(如 Channel、Buffer 操作),API 简洁易懂 |
| 可靠性 | 内置半包/粘包处理、断连重连、心跳检测等机制,解决网络编程常见问题 |
| 可扩展性 | 基于责任链模式的 ChannelPipeline,可灵活扩展自定义处理器(Handler) |
| 跨协议支持 | 支持 TCP、UDP、HTTP、WebSocket 等多种协议,提供丰富的编解码器 |
二、Netty 核心架构流程图
1. Netty 核心工作流程(Reactor 主从线程模型)
Reactor 模型是 Netty 的核心,主流使用「主从 Reactor 模型」(多线程),以下是完整流程图:
flowchart TD
subgraph 初始化阶段
A["创建 BossGroup(主 Reactor 线程组)<br/>负责监听客户端连接"] --> B["创建 WorkerGroup(从 Reactor 线程组)<br/>负责处理读写事件"]
B --> C["创建 ServerBootstrap(服务器启动器)"]
C --> D["配置线程组、通道类型(NioServerSocketChannel)"]
D --> E["配置 ChannelPipeline(责任链)<br/>添加编解码器、业务 Handler"]
E --> F["绑定端口,启动服务器"]
end
subgraph 连接处理阶段
F --> G["BossGroup 线程监听 ACCEPT 事件(新连接)"]
G --> H["BossGroup 接收 SocketChannel 连接"]
H --> I["将 SocketChannel 注册到 WorkerGroup 的某个线程"]
end
subgraph 读写事件处理阶段
I --> J["Worker 线程监听 READ/WRITE 事件"]
J --> K["事件触发后,通过 ChannelPipeline 传递事件"]
K --> L["Pipeline 中的 Handler 依次处理事件<br/>(解码→业务处理→编码→回写)"]
L --> M["处理完成后,返回结果给客户端"]
M --> J
end
subgraph 资源释放阶段
N["客户端断开连接"] --> O["Worker 线程取消 Channel 注册"]
O --> P["关闭 Channel,释放资源"]
end
%% 样式优化
classDef init fill:#e8f4f8,stroke:#3182ce,stroke-width:2px
classDef conn fill:#fdf2f8,stroke:#9f7aea,stroke-width:2px
classDef io fill:#f5f5f5,stroke:#48bb78,stroke-width:2px
classDef release fill:#fef7fb,stroke:#e53e3e,stroke-width:2px
class A,B,C,D,E,F init
class G,H,I conn
class J,K,L,M io
class N,O,P release
2. 流程图核心解读
- BossGroup:主线程组,通常只配置 1 个线程,专门负责监听客户端的连接请求(对应原生 NIO 的 ServerSocketChannel 监听 ACCEPT 事件);
- WorkerGroup:工作线程组,可配置多个线程,每个线程负责处理一个或多个 SocketChannel 的读写事件;
- ChannelPipeline:责任链模式,所有的 I/O 事件(连接、读、写)都会通过 Pipeline 中的 Handler 依次处理,开发者只需关注自定义业务 Handler;
- Handler:分为
ChannelInboundHandler(处理入站事件,如读数据)和ChannelOutboundHandler(处理出站事件,如写数据)。
三、Netty 核心组件说明
| 组件 | 作用 |
|---|---|
EventLoopGroup | 事件循环组,包含多个 EventLoop,BossGroup/WorkerGroup 都属于此类 |
ServerBootstrap | 服务器启动器,用于配置 Netty 服务器的核心参数(线程组、通道类型等) |
Channel | 通信通道,对应原生 NIO 的 Channel,封装了读写、连接等操作 |
ChannelPipeline | 责任链,管理所有 Handler,I/O 事件会在 Pipeline 中流转 |
ChannelHandler | 事件处理器,处理具体的业务逻辑(如解码、编码、业务处理) |
ByteBuf | Netty 自定义的缓冲区,替代原生 NIO 的 ByteBuffer,性能更高、更易用 |
Codec | 编解码器,处理网络传输中的半包/粘包问题(如 LineBasedFrameDecoder) |
四、Netty 完整示例代码(TCP 服务器 + 客户端)
以下是可直接运行的 Netty 服务器和客户端示例,实现「客户端发送消息,服务器接收并回显」的功能,包含核心的编解码、业务处理逻辑。
1. 前置依赖(Maven)
首先在 pom.xml 中引入 Netty 依赖(推荐使用稳定版 4.1.x):
<dependencies>
<!-- Netty 核心依赖 -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.94.Final</version>
</dependency>
</dependencies>
2. Netty 服务器代码
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
/**
* Netty TCP 服务器示例
* 功能:接收客户端消息,并回显「服务器已收到:xxx」
*/
public class NettyServer {
// 监听端口
private final int port;
public NettyServer(int port) {
this.port = port;
}
public void start() throws InterruptedException {
// 1. 创建 BossGroup 和 WorkerGroup
// BossGroup:处理客户端连接请求,默认线程数 = CPU 核心数 * 2
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
// WorkerGroup:处理读写事件,默认线程数 = CPU 核心数 * 2
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
// 2. 创建服务器启动器
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup) // 绑定线程组
.channel(NioServerSocketChannel.class) // 指定通道类型(NIO 模式)
.option(ChannelOption.SO_BACKLOG, 128) // 连接队列大小
.childOption(ChannelOption.SO_KEEPALIVE, true) // 开启心跳保活
.childHandler(new ChannelInitializer<SocketChannel>() {
// 3. 初始化 ChannelPipeline(责任链)
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// 添加编解码器:解决半包/粘包问题
pipeline.addLast(new LineBasedFrameDecoder(1024)); // 按行分割消息
pipeline.addLast(new StringDecoder()); // 字节转字符串
pipeline.addLast(new StringEncoder()); // 字符串转字节
// 添加自定义业务处理器
pipeline.addLast(new NettyServerHandler());
}
});
System.out.println("Netty 服务器已启动,监听端口:" + port);
// 4. 绑定端口,同步等待启动完成
ChannelFuture future = bootstrap.bind(port).sync();
// 5. 监听通道关闭事件,同步等待服务器关闭
future.channel().closeFuture().sync();
} finally {
// 6. 优雅关闭线程组
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
System.out.println("Netty 服务器已关闭");
}
}
public static void main(String[] args) throws InterruptedException {
new NettyServer(8080).start();
}
/**
* 自定义服务器业务处理器
* SimpleChannelInboundHandler:自动释放缓冲区,简化开发
*/
static class NettyServerHandler extends SimpleChannelInboundHandler<String> {
// 当接收到客户端消息时触发
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("收到客户端[" + ctx.channel().remoteAddress() + "]消息:" + msg);
// 回显消息给客户端(异步写操作)
ctx.writeAndFlush("服务器已收到:" + msg + "\n");
}
// 当客户端连接建立时触发
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("客户端[" + ctx.channel().remoteAddress() + "]已连接");
super.channelActive(ctx);
}
// 当客户端断开连接时触发
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("客户端[" + ctx.channel().remoteAddress() + "]已断开连接");
super.channelInactive(ctx);
}
// 异常处理
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close(); // 关闭通道
}
}
}
3. Netty 客户端代码
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import java.util.Scanner;
/**
* Netty TCP 客户端示例
* 功能:向服务器发送消息,并接收服务器回显
*/
public class NettyClient {
private final String host;
private final int port;
public NettyClient(String host, int port) {
this.host = host;
this.port = port;
}
public void start() throws InterruptedException {
// 1. 创建客户端事件循环组(客户端只需一个线程组)
EventLoopGroup group = new NioEventLoopGroup();
try {
// 2. 创建客户端启动器
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group) // 绑定线程组
.channel(NioSocketChannel.class) // 指定客户端通道类型
.option(ChannelOption.TCP_NODELAY, true) // 禁用 Nagle 算法,立即发送数据
.handler(new ChannelInitializer<SocketChannel>() {
// 3. 初始化 ChannelPipeline
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// 与服务器保持一致的编解码器
pipeline.addLast(new LineBasedFrameDecoder(1024));
pipeline.addLast(new StringDecoder());
pipeline.addLast(new StringEncoder());
// 添加自定义客户端处理器
pipeline.addLast(new NettyClientHandler());
}
});
// 4. 连接服务器
ChannelFuture future = bootstrap.connect(host, port).sync();
System.out.println("已连接到 Netty 服务器:" + host + ":" + port);
// 5. 读取控制台输入,发送给服务器
Channel channel = future.channel();
Scanner scanner = new Scanner(System.in);
System.out.println("请输入要发送的消息(输入 exit 退出):");
while (scanner.hasNextLine()) {
String msg = scanner.nextLine();
if ("exit".equals(msg)) {
channel.close(); // 关闭通道
break;
}
// 发送消息(末尾加换行符,匹配服务器的 LineBasedFrameDecoder)
channel.writeAndFlush(msg + "\n");
}
// 6. 等待通道关闭
channel.closeFuture().sync();
} finally {
// 7. 优雅关闭线程组
group.shutdownGracefully();
System.out.println("Netty 客户端已关闭");
}
}
public static void main(String[] args) throws InterruptedException {
new NettyClient("localhost", 8080).start();
}
/**
* 自定义客户端业务处理器
*/
static class NettyClientHandler extends SimpleChannelInboundHandler<String> {
// 接收服务器回显的消息
@Override
protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
System.out.println("收到服务器回显:" + msg);
}
// 异常处理
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
}
4. 代码运行说明
- 先启动
NettyServer,控制台输出「Netty 服务器已启动,监听端口:8080」; - 再启动
NettyClient,控制台输出「已连接到 Netty 服务器:localhost:8080」; - 在客户端控制台输入任意消息(如「Hello Netty」),服务器会接收并回显,客户端能看到服务器的回复;
- 输入「exit」可关闭客户端,服务器会提示「客户端已断开连接」。
5. 核心代码解读
- 编解码器:
LineBasedFrameDecoder按换行符分割消息,解决了网络传输中的「半包/粘包」问题(原生 NIO 需要手动处理,Netty 内置解决); - Handler 设计:
SimpleChannelInboundHandler自动释放 ByteBuf 内存,避免内存泄漏; - 异步操作:
writeAndFlush是异步写操作,Netty 会通过 EventLoop 异步处理,不会阻塞主线程; - 优雅关闭:
shutdownGracefully()会等待所有任务完成后再关闭线程组,避免资源泄漏。
五、Netty 典型应用场景
- 中间件通信:Dubbo、Spring Cloud Gateway 等微服务框架的底层通信;
- 消息队列:RocketMQ、Kafka 的网络通信模块;
- 大数据:Hadoop、Spark 的分布式通信;
- 即时通信:基于 WebSocket 的聊天系统、推送系统;
- 游戏服务器:高并发的游戏实时通信(如王者荣耀、英雄联盟的后台)。
总结
- Netty 核心定位:基于 Java NIO 的高性能网络编程框架,封装了原生 NIO 的复杂性,提供简洁的 API 和可靠的网络通信能力;
- 核心架构:采用主从 Reactor 线程模型,BossGroup 处理连接、WorkerGroup 处理读写,通过 ChannelPipeline 责任链处理业务逻辑;
- 核心优势:开箱即用的编解码器、半包/粘包处理、高并发支持,是 Java 高性能网络编程的首选框架,广泛应用于中间件、大数据、游戏等领域。