Spring 中 Netty 的应用完全指南

Spring 中 Netty 的应用完全指南

基于 Spring Boot 3.x + Netty 4.1.x服务端、客户端、WebFlux、WebSocket 四合一实践 含 完整源码、生命周期、线程模型、自动配置 解析


目录

  1. 背景:为什么要在 Spring 里用 Netty
  2. 整体架构
  3. 场景一:内嵌 Netty 作为 Web 容器
  4. 场景二:自定义 TCP/UDP 服务器
  5. 场景三:WebSocket 长连接
  6. Spring Boot 自动装配源码走读
  7. 生命周期与线程模型
  8. 最佳实践与性能调优
  9. 常见问题 FAQ
  10. 总结

背景

  • Tomcat/Jetty 是阻塞式 Servlet 容器,高并发场景下线程消耗大。
  • Netty 采用 NIO + 事件驱动 ,单线程可支撑 万级连接
  • Spring Boot 3.x 官方支持 WebFluxReactor Netty,整合更丝滑。

整体架构

场景一:内嵌 Netty 作为 Web 容器(WebFlux)

1. 引入依赖

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

spring-boot-starter-webflux 默认使用 Reactor Netty(Netty 的响应式封装)。

2. 自定义配置(可选)

typescript 复制代码
@Configuration
public class NettyWebFluxConfig implements WebServerFactoryCustomizer<NettyReactiveWebServerFactory> {
    @Override
    public void customize(NettyReactiveWebServerFactory factory) {
        factory.addServerCustomizers(httpServer ->
                httpServer
                 .port(9000)
                 .option(ChannelOption.SO_BACKLOG, 1024)
                 .childOption(ChannelOption.TCP_NODELAY, true)
        );
    }
}

3. 路由示例

typescript 复制代码
@SpringBootApplication
public class WebFluxApplication {
    public static void main(String[] args) {
        SpringApplication.run(WebfluxApplication.class, args);
    }
​
    @Bean
    public RouterFunction<ServerResponse> route() {
        return RouterFunctions
                .route(GET("/hello"), req -> ServerResponse.ok().bodyValue("Hello Netty"));
    }
}

访问 http://localhost:9000/hello 即可返回 Hello Netty


场景二:自定义 TCP/UDP 服务器

1. Maven 依赖

xml 复制代码
<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.110.Final</version>
</dependency>

2. 启动器(跟随 Spring 生命周期)

typescript 复制代码
@Component
public class TcpServer implements SmartLifecycle {
​
    private final EventLoopGroup boss = new NioEventLoopGroup(1);
    private final EventLoopGroup worker = new NioEventLoopGroup(0);
    private Channel channel;
​
    @Override
    public void start() {
        try {
            ServerBootstrap bootstrap = new ServerBootstrap()
                    .group(boss, worker)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) {
                            ChannelPipeline p = ch.pipeline();
                            p.addLast(new StringDecoder());
                            p.addLast(new StringEncoder());
                            p.addLast(new SimpleChannelInboundHandler<String>() {
                                @Autowired
                                private EchoService service; // Spring 注入
                                @Override
                                protected void channelRead0(ChannelHandlerContext ctx, String msg) {
                                    ctx.writeAndFlush(service.echo(msg));
                                }
                            });
                        }
                    });
            channel = bootstrap.bind(8888).sync().channel();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
​
    @Override
    public void stop() {
        if (channel != null) channel.close();
        boss.shutdownGracefully();
        worker.shutdownGracefully();
    }
​
    @Override
    public boolean isRunning() {
        return channel != null && channel.isActive();
    }
}

3. 业务 Service

typescript 复制代码
@Service
public class EchoService {
    public String echo(String msg) {
        return "Echo: " + msg;
    }
}

场景三:WebSocket 长连接

java 复制代码
@Component
public class WebSocketServer implements SmartLifecycle {
​
    @Override
    public void start() throws Exception {
        ServerBootstrap bootstrap = new ServerBootstrap()
                .group(new NioEventLoopGroup(1), new NioEventLoopGroup())
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) {
                        ch.pipeline()
                          .addLast(new HttpServerCodec())
                          .addLast(new HttpObjectAggregator(65536))
                          .addLast(new WebSocketServerProtocolHandler("/ws"))
                          .addLast(new SimpleChannelInboundHandler<TextWebSocketFrame>() {
                              @Override
                              protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame frame) {
                                  ctx.writeAndFlush(new TextWebSocketFrame("Received: " + frame.text()));
                              }
                          });
                    }
                });
        bootstrap.bind(9999).sync();
    }
}

客户端连接 ws://localhost:9999/ws 即可实时通信。


Spring Boot 自动装配源码走读

1. 入口:ReactorNettyAutoConfiguration

less 复制代码
@AutoConfiguration
@ConditionalOnClass(HttpServer.class)
@EnableConfigurationProperties(ServerProperties.class)
public class ReactorNettyAutoConfiguration {
​
    @Bean
    public NettyReactiveWebServerFactory nettyReactiveWebServerFactory() {
        return new NettyReactiveWebServerFactory();
    }
}

2. 工厂创建 ServerBootstrap

scala 复制代码
public class NettyReactiveWebServerFactory extends AbstractReactiveWebServerFactory {
    @Override
    public WebServer getWebServer(HttpHandler httpHandler) {
        return new NettyWebServer(
                HttpServer.create()
                          .port(getPort())
                          .handle(new ReactorHttpHandlerAdapter(httpHandler))
        );
    }
}

生命周期与线程模型

阶段 线程 说明
启动 主线程 Spring Boot SmartLifecycle
Accept Boss EventLoop 单线程处理连接事件
I/O Worker EventLoop 多线程处理读写
业务 Worker 或自定义线程池 耗时任务外移

最佳实践

建议 配置
线程数 Boss=1,Worker=CPU*2
ChannelOption SO_BACKLOG=1024, TCP_NODELAY=true
ChannelHandler 使用 @Sharable 保证单例
内存 ByteBuf.release() 避免泄漏

常见问题 FAQ

问题 解决
端口冲突 server.portnetty.port 分离
Handler 非 Spring Bean 使用 @Component + @Autowired
优雅关闭 EventLoopGroup.shutdownGracefully()

总结

  • Spring Boot + Netty = 阻塞逻辑非阻塞 I/O 的完美结合
  • WebFlux 内置,自定义 TCP/UDP/WebSocket 三行代码即可
  • 掌握 生命周期、线程模型、ChannelOption ,即可构建 万级并发 的 Spring 应用!
相关推荐
不知更鸟11 小时前
Django 项目设置流程
后端·python·django
黄昏恋慕黎明13 小时前
spring MVC了解
java·后端·spring·mvc
G探险者15 小时前
为什么 VARCHAR(1000) 存不了 1000 个汉字? —— 详解主流数据库“字段长度”的底层差异
数据库·后端·mysql
百锦再15 小时前
第18章 高级特征
android·java·开发语言·后端·python·rust·django
Tony Bai15 小时前
Go 在 Web3 的统治力:2025 年架构与生态综述
开发语言·后端·架构·golang·web3
程序猿202315 小时前
项目结构深度解析:理解Spring Boot项目的标准布局和约定
java·spring boot·后端
RainbowSea15 小时前
内网穿透配置和使用
java·后端
掘金码甲哥16 小时前
网关上的限流器
后端
q***062916 小时前
搭建Golang gRPC环境:protoc、protoc-gen-go 和 protoc-gen-go-grpc 工具安装教程
开发语言·后端·golang
GOTXX17 小时前
用Rust实现一个简易的rsync(远程文件同步)工具
开发语言·后端·rust