Netty 是 JBoss 开源的高性能网络框架,封装了 Java NIO 的复杂性。本文记录学习笔记。
为什么需要 Netty?
Java 原生网络编程有 BIO、NIO、AIO 三种方式:
| 方案 | 复杂度 | 性能 | 问题 |
|---|---|---|---|
| BIO | 简单 | 低 | 一线程一连接,资源浪费 |
| NIO | 极难 | 中 | Selector 空转 bug、ByteBuffer 指针易错、内存泄漏 |
| AIO | 复杂 | 中 | Linux 实现不佳 |
Netty 解决了原生 NIO 的所有痛点:封装 Selector、提供读写双指针 ByteBuf、内置编解码器、丰富的协议支持。
核心架构
ServerBootstrap
├─ Boss EventLoopGroup (1 线程,accept 新连接)
├─ Worker EventLoopGroup (多线程,处理 I/O)
│ └─ EventLoop → Channel (TCP 连接)
└─ ChannelPipeline (责任链)
└─ Head → Decoder → BusinessHandler → Tail
核心组件:
| 组件 | 职责 |
|---|---|
| EventLoop | 单线程处理多个 Channel 的 I/O 事件 |
| Channel | 代表一个网络连接 |
| ChannelPipeline | 处理器责任链 |
| ByteBuf | 读写双指针字节容器 |
Spring Boot 集成方式
有三种方式:
| 方式 | 场景 | 启动方式 |
|---|---|---|
| WebFlux | 替代 Tomcat,高并发 API | 自动 |
| 独立 Netty 服务 | TCP/WebSocket 自定义协议 | @PostConstruct |
| WebClient | HTTP 客户端调用 | 调用时自动 |
方式一:WebFlux(Netty 作为 Web 容器)
引入 spring-boot-starter-webflux,默认用 Netty 替代 Tomcat:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
Controller 返回 Mono/Flux 即可。
方式二:独立 Netty 服务
Spring Boot 管理 Bean,Netty 作为独立网络服务启动:
@Component
public class NettyTcpServer {
@PostConstruct
public void start() {
EventLoopGroup boss = new NioEventLoopGroup(1);
EventLoopGroup worker = new NioEventLoopGroup();
new Thread(() -> {
ServerBootstrap b = new ServerBootstrap();
b.group(boss, worker)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
ch.pipeline()
.addLast(new Decoder())
.addLast(new Encoder())
.addLast(new BusinessHandler());
}
});
b.bind(8090).sync();
}).start();
}
}
实战:TCP 自定义协议
协议设计
| 魔数(2B) | 类型(1B) | body长度(4B) | body(NB) |
| 0xAABB | | | |
编解码器
// 编码器:Java对象 -> 字节流
public class MessageEncoder extends MessageToByteEncoder<Message> {
@Override
protected void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) {
out.writeShort(0xAABB);
out.writeByte(msg.getType());
out.writeInt(msg.getBodyLength());
out.writeBytes(msg.getBody());
}
}
// 解码器:字节流 -> Java对象
public class MessageDecoder extends ByteToMessageDecoder {
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
if (in.readableBytes() < 7) return;
in.markReaderIndex();
if (in.readShort() != 0xAABB) { ctx.close(); return; }
}
}
实战:WebSocket 高并发推送
Netty WebSocket 单机支持数万长连接,远超 Tomcat。
ch.pipeline()
.addLast(new HttpServerCodec())
.addLast(new HttpObjectAggregator(65536))
.addLast(new WebSocketServerProtocolHandler("/ws"))
.addLast(new WebSocketFrameHandler());
帧处理器广播消息:
private static final ChannelGroup channels = new DefaultChannelGroup(...);
@Override
protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) {
if (frame instanceof TextWebSocketFrame) {
channels.writeAndFlush(new TextWebSocketFrame("广播消息"));
}
}
生产最佳实践
优雅关闭
@PreDestroy
public void stop() {
serverChannel.close();
bossGroup.shutdownGracefully(5, 10, TimeUnit.SECONDS);
}
心跳检测
ch.pipeline().addLast(new IdleStateHandler(0, 30, 0, TimeUnit.SECONDS));
连接限流
if (counter.incrementAndGet() > MAX_CONNECTIONS) {
ctx.close();
}
内存管理
使用 PooledByteBufAllocator,SimpleChannelInboundHandler 自动释放 ByteBuf。
Netty vs Tomcat WebSocket
| 维度 | Netty | Tomcat |
|---|---|---|
| 连接上限 | 10万+ | 1~2万 |
| 每连接内存 | ~6KB | ~1MB |
| Spring 集成 | 手动 | 开箱即用 |
| 适用场景 | IoT、游戏、高并发推送 | 企业 Web 应用 |
选择建议: 连接数 < 5000 用 Tomcat;> 1 万用 Netty。
总结
Netty 在 Spring Boot 的核心用法:
- WebFlux:替代 Tomcat,响应式 API
- 独立服务:自定义 TCP/WebSocket,
@PostConstruct启动 - WebClient:HTTP 客户端,底层是 Reactor Netty
记住 Pipeline 模式:入站 Decoder -> Handler,出站 Encoder <- Tail。