1. 概述
Spring 5 引入了 Spring WebFlux,为 Web 应用提供了响应式编程的支持。这意味着你可以构建非阻塞、事件驱动的服务,显著提升 I/O 密集型应用的吞吐能力。
本文将带你使用 @RestController
和 WebClient
构建一个轻量级的响应式 REST 应用,并集成 Spring Security 实现接口级别的权限控制。
✅ 适合场景:高并发、长连接、数据流式传输(如实时通知、日志推送)
❌ 不适合场景:CPU 密集型任务(如复杂计算)
2. Spring WebFlux 框架核心
WebFlux 内部基于 Project Reactor,依赖其两个核心发布者类型:
- ✅
Flux<T>
:发布 0..N 个元素的数据流 - ✅
Mono<T>
:发布 0..1 个元素的单值流
它支持两种编程模型:
- 注解式(基于
@Controller
/@RestController
) - 函数式路由(Functional Endpoints)
本文聚焦于注解式开发,函数式风格我们已在其他文章中详细探讨过。
⚠️ 注意:WebFlux 并不依赖 Servlet 容器,虽然它也能运行在 Servlet 容器上(如 Tomcat),但推荐搭配 Netty 或 Undertow 以发挥完全的非阻塞优势。
3. 项目依赖
引入 spring-boot-starter-webflux
即可自动装配所有必要组件:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<version>3.1.2</version>
</dependency>
该 Starter 自动包含:
spring-boot
和spring-boot-starter
:基础启动器spring-webflux
:响应式 Web 框架核心reactor-core
:响应式流实现reactor-netty
:默认的非阻塞 HTTP 客户端/服务器
📌 最新版本可从 Maven Central 获取。
4. 响应式 REST 应用设计
我们将构建一个简单的 EmployeeManagement
示例应用,涵盖以下功能:
- 领域模型:
Employee
(含 id、name) - 使用
@RestController
提供响应式 REST 接口 - 使用
WebClient
编写响应式客户端 - 使用 Spring Security 保护敏感接口
5. 响应式 @RestController
WebFlux 的注解式控制器与 Spring MVC 高度相似,但返回值是响应式类型(Mono
/ Flux
)。
先定义控制器骨架:
@RestController
@RequestMapping("/employees")
public class EmployeeController {
private final EmployeeRepository employeeRepository;
public EmployeeController(EmployeeRepository employeeRepository) {
this.employeeRepository = employeeRepository;
}
}
EmployeeRepository
需要是一个支持响应式流的仓库,比如基于 Spring Data R2DBC 或 MongoDB Reactive Driver 实现。
5.1 获取单个资源
返回单个员工信息,使用 Mono<Employee>
包装:
@GetMapping("/{id}")
public Mono<Employee> getEmployeeById(@PathVariable String id) {
return employeeRepository.findEmployeeById(id);
}
✅ 为什么用 Mono
?
因为根据 ID 查询最多返回一个结果,符合 0..1
的语义。
5.2 获取资源集合
获取所有员工列表,使用 Flux<Employee>
:
@GetMapping
public Flux<Employee> getAllEmployees() {
return employeeRepository.findAllEmployees();
}
✅ 为什么用 Flux
?
集合数据是典型的 0..N
数据流,Flux
支持逐个发射元素,适合流式传输。
6. 响应式 Web Client
WebClient
是 Spring 5 推出的非阻塞 HTTP 客户端,取代了旧的 RestTemplate
,完美支持响应式流。
创建一个简单的客户端:
public class EmployeeWebClient {
WebClient client = WebClient.create("http://localhost:8080");
}
通过工厂方法 create()
初始化,指定基础 URL 后,后续请求可使用相对路径。
6.1 获取单个资源
调用 /employees/{id}
接口获取单个员工:
Mono<Employee> employeeMono = client.get()
.uri("/employees/{id}", "1")
.retrieve()
.bodyToMono(Employee.class);
employeeMono.subscribe(System.out::println);
⚠️ 注意:.subscribe()
触发实际请求。在生产环境中应避免直接 subscribe
,推荐通过 map/flatMap
继续链式操作或返回给上游。
6.2 获取资源集合
调用 /employees
获取员工列表:
Flux<Employee> employeeFlux = client.get()
.uri("/employees")
.retrieve()
.bodyToFlux(Employee.class);
employeeFlux.subscribe(System.out::println);
bodyToFlux
会逐个解析响应流中的对象,适合处理大数据量集合。
📌 更多 WebClient
高级用法(如错误处理、过滤器、超时设置)可参考我们关于 WebClient 详解 的文章。
7. Spring WebFlux 安全控制
使用 Spring Security 可以轻松保护响应式接口。我们新增一个更新员工信息的接口,并限制仅 ADMIN
角色可访问。
7.1 添加受保护接口
@PostMapping("/update")
public Mono<Employee> updateEmployee(@RequestBody Employee employee) {
return employeeRepository.updateEmployee(employee);
}
这是一个典型的写操作,需要权限控制。
7.2 配置安全规则
创建安全配置类:
@EnableWebFluxSecurity
public class EmployeeWebSecurityConfig {
@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http.csrf().disable()
.authorizeExchange()
.pathMatchers(HttpMethod.POST, "/employees/update").hasRole("ADMIN")
.pathMatchers("/**").permitAll()
.and()
.httpBasic();
return http.build();
}
}
关键点说明:
- ✅
@EnableWebFluxSecurity
:启用 WebFlux 环境下的安全支持 - ✅
ServerHttpSecurity
:响应式安全配置 DSL - ✅
authorizeExchange()
:用于路由级别的权限判断(类比 MVC 中的authorizeRequests
) - ✅
httpBasic()
:启用 HTTP Basic 认证(测试方便,生产建议用 JWT)
📌 此配置确保只有拥有 ADMIN
角色的用户才能调用 /employees/update
接口。
📌 更详细的 WebFlux 安全配置可参考 Spring Security 5 响应式安全实践。
8. 总结
本文通过一个简单的 Employee
示例,展示了如何使用 Spring WebFlux 构建响应式 REST 服务:
- 使用
@RestController
返回Mono
/Flux
实现非阻塞接口 - 使用
WebClient
编写响应式客户端,消费流式数据 - 使用
@EnableWebFluxSecurity
和ServerHttpSecurity
保护敏感接口
除此之外,WebFlux 还支持:
- ✅ 响应式 WebSocket:实现双向流通信
- ✅
WebSocketClient
:响应式 WebSocket 客户端
📌 想了解如何使用响应式 WebSocket?查看我们深入讲解 Spring 5 响应式 WebSocket 的文章。
✅ 完整示例代码已托管至 GitHub:
https://github.com/example/spring-reactive-demo(原链接为示例 mock)