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 应用!
相关推荐
华仔啊3 分钟前
别再问了!Java里这几种场景,用抽象类就对了
java·后端
guojl6 分钟前
Gateway源码分析
后端·微服务
tingting011922 分钟前
Spring Boot 外部配置指定不生效的原因与解决
java·spring boot·后端
2501_9096867032 分钟前
基于SpringBoot的网上点餐系统
java·spring boot·后端
天天摸鱼的java工程师39 分钟前
聊聊线程池中哪几种状态,分别表示什么?8 年 Java 开发:从业务踩坑到源码拆解(附监控实战)
java·后端
杨杨杨大侠43 分钟前
第4篇:AOP切面编程 - 无侵入式日志拦截
java·后端·开源
IT_陈寒2 小时前
Python 3.12 新特性实战:5个让你的代码效率提升50%的技巧!🔥
前端·人工智能·后端
Apifox2 小时前
Apifox 8 月更新|新增测试用例、支持自定义请求示例代码、提升导入/导出 OpenAPI/Swagger 数据的兼容性
前端·后端·测试