Netty 学习笔记

星期三, 5月 27, 2026 | 2分钟阅读 | 更新于 星期三, 5月 27, 2026

@

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
WebClientHTTP 客户端调用调用时自动

方式一: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();
}

内存管理

使用 PooledByteBufAllocatorSimpleChannelInboundHandler 自动释放 ByteBuf。

Netty vs Tomcat WebSocket

维度NettyTomcat
连接上限10万+1~2万
每连接内存~6KB~1MB
Spring 集成手动开箱即用
适用场景IoT、游戏、高并发推送企业 Web 应用

选择建议: 连接数 < 5000 用 Tomcat;> 1 万用 Netty。

总结

Netty 在 Spring Boot 的核心用法:

  1. WebFlux:替代 Tomcat,响应式 API
  2. 独立服务:自定义 TCP/WebSocket,@PostConstruct 启动
  3. WebClient:HTTP 客户端,底层是 Reactor Netty

记住 Pipeline 模式:入站 Decoder -> Handler,出站 Encoder <- Tail。

© 2026 My Blog

🌱 Powered by Hugo with theme Dream.