Spring WebFlux 是 Spring 5(2017)引入的响应式 Web 框架,与基于 Servlet 的 Spring MVC 并列。Boot 总览见 Spring Boot;若只需提升并发能力而不改编程模型,可先看 Java Virtual Threads。

解决的问题

传统 Spring MVC 基于 Servlet 模型,每个请求占用一个线程,调用数据库或外部 API 时线程阻塞等待:

请求进来 → 分配线程 → 调用数据库(等待 100ms,线程阻塞)→ 调用外部 API(等待 200ms,线程阻塞)→ 返回

Tomcat 默认线程池约 200 个线程,高并发下线程池耗尽,后续请求排队。

Spring WebFlux 引入响应式编程模型,底层使用 Netty(非 Servlet 容器),少量线程处理大量并发:

请求进来 → 少量线程(CPU 核数)→ 发起数据库查询(注册回调,线程立刻去处理其他请求)→ 数据返回时触发回调继续处理

编程模型

WebFlux 使用 Reactor 库的 Mono<T>(0 或 1 个异步结果)和 Flux<T>(0 到 N 个异步结果):

// Spring MVC(同步阻塞)
@GetMapping("/users/{id}")
public User getUser(@PathVariable Long id) {
    return userService.findById(id);  // blocks on DB
}

// Spring WebFlux(异步非阻塞)
@GetMapping("/users/{id}")
public Mono<User> getUser(@PathVariable Long id) {
    return userService.findById(id);  // returns a deferred result
}

WebFlux 的局限

  • 编程模型与传统命令式完全不同,调试困难,学习成本高
  • 需要支持响应式的驱动(R2DBC 替代 JDBC),不是所有库都有响应式版本
  • Java 21 虚拟线程的出现大幅削弱了 WebFlux 在普通业务系统里的核心优势(见 Java Virtual Threads)

何时仍选 WebFlux

  • SSE 实时推送
  • 需要背压控制(消费者告知生产者降速)的流式处理
  • 已有 WebFlux 项目:继续用即可,不必为并发改回 MVC

Java 网络层全景

主流 Java Web 栈最终归为两大谱系:

Servlet 容器系:  Tomcat / Jetty / Undertow
Netty 系:        Netty(或包装 Netty 的 Vert.x)

Undertow

Red Hat / JBoss 出品,Spring Boot 把它作为与 Tomcat、Jetty 并列的一等选项:排除默认 spring-boot-starter-tomcat、引入 spring-boot-starter-undertow 即可。支持 HTTP/1.1、HTTP/2、WebSocket、TLS,非阻塞 IO,比 Tomcat 更轻;Quarkus 默认用它。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-undertow</artifactId>
</dependency>

其它框架的网络层

框架 网络层 备注
Quarkus Vert.x → Netty Red Hat,云原生
Micronaut Netty 编译期 DI,快速启动
Helidon SE Netty Oracle
Vert.x Netty 多语言、事件驱动
gRPC-Java Netty gRPC 协议

Tomcat vs Netty:只是 IO 模型不同

二者解决的协议级问题相同(HTTP/1.1、HTTP/2、WebSocket、TLS 都支持),差别只在 IO 模型:

Tomcat/Jetty/Undertow Netty
IO 模型 阻塞(+ 虚拟线程) 非阻塞异步
编程模型 同步,简单 异步,复杂
调试 堆栈清晰 响应式链路复杂

WebFlux 用 Netty 替换 Tomcat,协议复杂度并未消失,只是从 Tomcat 转移到 Netty。

Netty 相对虚拟线程仍占优的场景

Java 21 虚拟线程让阻塞 IO 几乎零成本(见 Java Virtual Threads),多数业务用 Spring MVC + 虚拟线程即可。Netty / WebFlux 仍胜出的场景:

场景 原因
背压控制 响应式流让消费者告知生产者降速;虚拟线程无对应机制
单连接内存 EventLoop 模型开销低于虚拟线程(每个虚拟线程有可增长的栈,初始约 1KB)
流式响应 Flux<T> 原生逐块发送;Servlet 仍是请求-响应

参考

维护记录

时间 修改内容 原因
2026-06-27 新增「Java 网络层全景」(Undertow、各框架网络层、Tomcat vs Netty IO 模型、Netty 占优场景) 合并 comments-tree 启动打包文档相关章节