Spring Webflux 教程
1、概览
Spring 5 引入了 Spring WebFlux 框架,为 Web 应用提供响应式编程支持。
本文将带你了解如何使用响应式 Web 组件 RestController
和 WebClient
创建一个小型响应式 REST 应用,以及如何使用 Spring Security 来保护响应式端点。
2、Spring WebFlux 框架
Spring WebFlux 内部使用 Project Reactor 及其 Publisher(发布者)实现、Flux
和 Mono
。
WebFlux 支持两种编程模式:
- 基于注解的响应式组件
- 函数式路由和处理
本文重点介绍基于注解的响应式组件。
3、依赖
首先从 spring-boot-starter-webflux
依赖开始。
它会传递依赖其他所有的依赖:
spring-boot
和spring-boot-starter
,用于基本的 Spring Boot 应用设置spring-webflux
框架- 响应式流(Reactive Stream)所需的
reactor-core
以及reactor-netty
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<version>3.1.2</version>
</dependency>
可从 Maven Central 下载最新的 spring-boot-starter-webflux。
4、响应式 REST 应用
现在,使用 Spring WebFlux 构建一个非常简单的响应式 REST EmployeeManagement
应用:
- 使用
Employee
Model - 有id
和name
字段。 - 使用
RestController
构建 REST API,以单个资源和集合的形式发布Employee
资源。 - 使用
WebClient
创建客户端,检索相同的资源。 - 使用 WebFlux 和 Spring Security 创建安全的响应式端点
5、响应式 RestController
Spring WebFlux 与 Spring Web MVC 框架一样支持基于注解的配置。
首先,创建一个基于注解的 Controller EmployeeController
,用于发布 Employee
资源的响应式流。
@RestController
@RequestMapping("/employees")
public class EmployeeController {
private final EmployeeRepository employeeRepository;
// 构造函数
}
EmployeeRepository
可以是任何支持非阻塞响应式流的 Data Repository。
5.1、单个资源
然后,在 Controller 中创建一个端点,用于发布单个 Employee
资源:
@GetMapping("/{id}")
public Mono<Employee> getEmployeeById(@PathVariable String id) {
return employeeRepository.findEmployeeById(id);
}
如上,使用 Mono
封装了一个 Employee
资源,因为最多只能返回一个 Employee
。
5.2、资源集合
再添加一个端点,用于发布所有 Employees
的集合资源:
@GetMapping
public Flux<Employee> getAllEmployees() {
return employeeRepository.findAllEmployees();
}
对于集合资源,使用 Employee
类型的 Flux
,因为它是 0...n
个元素的发布者。
6、响应式 Web 客户端
Spring 5 中引入的 WebClient,是一种支持响应式流的非阻塞客户端。
使用 WebClient
创建一个客户端,以从 EmployeeController
提供的端点检索数据。
创建一个 EmployeeWebClient
:
public class EmployeeWebClient {
WebClient client = WebClient.create("http://localhost:8080");
// ...
}
如上,使用其工厂方法 create
创建了一个 WebClient
。它将指向 localhost:8080
,因此可以使用相对 URL 来调用该客户端实例。
6.1、检索单个资源
从端点 /employee/{id}
获取 Mono
类型的单个资源:
Mono<Employee> employeeMono = client.get()
.uri("/employees/{id}", "1")
.retrieve()
.bodyToMono(Employee.class);
employeeMono.subscribe(System.out::println);
6.2、检索资源集合
同样,从端点 /employees
获取 Flux
类型的集合资源:
Flux<Employee> employeeFlux = client.get()
.uri("/employees")
.retrieve()
.bodyToFlux(Employee.class);
employeeFlux.subscribe(System.out::println);
关于 WebClient 的更多详细用法,你可以参考 这篇教程。
7、Spring WebFlux 安全设置
可以使用 Spring Security 来保护响应式端点。
接着,我们要在 EmployeeController
中新建了一个端点。这个端点会更新 Employee
的详细信息,并将更新后的 Employee
信息响应回来。
由于这允许用户更改现有的 Employee
数据,所以将此端点限制为只能由 ADMIN
角色用户使用。
在 EmployeeController
中添加一个新方法:
@PostMapping("/update")
public Mono<Employee> updateEmployee(@RequestBody Employee employee) {
return employeeRepository.updateEmployee(employee);
}
创建 SecurityConfig
并定义一些基于路径的规则来限制对该方法的访问。
只允许 ADMIN
用户访问 /employees/update
端点:
@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();
}
}
此配置会限制对 /employees/update
端点的访问。只有角色为 ADMIN
的用户才能访问该端点并更新现有 Employee
。
最后,注解 @EnableWebFluxSecurity
通过一些默认配置添加了 Spring Security WebFlux 支持。
关于 Spring Security 的更多用法,你可以参考 Spring Security 中文文档。
8、总结
本文介绍了如何使用 Spring WebFlux 创建响应式 Web 应用。通过实际案例演示了如何使用 RestController 和 WebClient 发布和消费响应式流,以及如何使用 Spring Security 保护响应式端点。
Ref:https://www.baeldung.com/spring-webflux