原文链接:http://www.baeldung.com/spring-webflux

1. 概览

Spring WebFlux 框架是 Spring 5的一部分,他为 web 应用提供了响应式编程的支持。

在本文中,我们将使用响应式注解RestControllerWebClient创建一个小的 REST 应用,

我们还将研究如何使用Spring Security保护我们的响应式端点。

2. Spring WebFlux 框架

Spring WebFlux内部使用Project Reactor及其发布者实现 - Flux和Mono。

这个新框架支持下面两种编程模型:

  • 基于注释的响应式组件
  • 函数级别的路由和处理

在这里,我们将重点关注基于注释的响应式组件,正如我们已经研究过的functional style – routing and handling.

3. 依赖

让我们从spring-boot-starter-webflux依赖开始,它包含了所有其他必需的依赖:

  • 用于基本Spring Boot应用程序设置的spring-boot和spring-boot-starter
  • spring-webflux框架
  • 我们使用 reactive streams 和 reactor-netty需要的reactor-core

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
        <version>2.0.3.RELEASE</version>
    </dependency>

最新的spring-boot-starter-webflux 可以从Maven Central下载。

4. 响应式 REST 应用

我们将使用 Spring WebFlux 来创建一个非常简单的响应式 REST 员工管理应用:

  • 我们将使用一个简单的域模型 - 具有id和name字段的Employee
  • 我们将使用RestController和WebClient构建REST API,用于发布和检索Single以及Collection Employeeresources
  • 我们还将使用WebFlux和Spring Security创建安全的响应式端点

5. 响应式的 RestController

Spring WebFlux和Spring Web MVC框架一样,都支持基于注释的配置。

首先,在服务器端,我们创建一个带注释的控制器,用于发布我们的Employee反应流。

让我们创建带注释的EmployeeController:

@RestController
@RequestMapping("/employees")
public class EmployeeReactiveController {
 
    private final EmployeeRepository employeeRepository;
     
    // constructor...
}

EmployeeRepository可以是支持非阻塞响应流的任何数据存储库。

5.1. 单一资源

让我们在控制器中创建一个发布单个Employee资源的端点

@GetMapping("/{id}")
private Mono<Employee> getEmployeeById(@PathVariable String id) {
    return employeeRepository.findEmployeeById(id);
}

对于单个Employee资源,我们使用了Employee类型的Mono,因为它最多会发出1个元素。

5.2. 集合资源

我们还在我们的控制器中添加一个端点,用于发布所有Employees的集合资源:

@GetMapping
private Flux<Employee> getAllEmployees() {
    return employeeRepository.findAllEmployees();
}

对于集合资源,我们使用了Employee类型的Flux - 因为那是发布者专注于发出0..n元素。

6. 响应式 web 客户端

在Spring 5中引入的WebClient是一个支持Reactive Streams的非阻塞客户端。

在客户端,我们使用WebClient从EmployeeController中创建的端点检索数据。

让我们创建一个简单的EmployeeWebClient:

public class EmployeeWebClient {
 
    WebClient client = WebClient.create("http://localhost:8080");
 
    // ...
}

这里我们使用其工厂方法create创建了一个WebClient。 对于相对URL,它将指向localhost:8080。

6.1. 获取单一资源

To retrieve single resource of type Mono from endpoint /employee/{id}:

/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);

详细的说明参考这篇文章 setting up and working with WebClient.

7. Spring WebFlux Security

我们可以使用 Spring Security 来对我们的响应式端点进行加密.

假设我们的EmployeeController中有一个新的端点。 此端点更新Employee详细信息并返回更新后的Employee

由于这允许用户更改现有员工,因此我们希望仅将此端点限制为ADMIN角色用户。

让我们为EmployeeController添加一个新方法:

@PostMapping("/update")
private Mono<Employee> updateEmployee(@RequestBody Employee employee) {
    return employeeRepository.updateEmployee(employee);
}

现在,为了限制对此方法的访问,让我们创建SecurityConfig并定义一些基于路径的规则来保证仅允许ADMIN用户:

@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支持。

更详细的说明参见 configuring and working with Spring WebFlux security.

8. 总结

在本文中,我们通过创建一个小型的Reactive REST应用程序,探索了如何创建和使用Spring WebFlux框架支持的反应式Web组件。

我们学习了如何使用RestController和WebClient分别发布和使用反应流。

我们还研究了如何在Spring Security的帮助下创建安全的反应端点。

除了Reactive RestController和WebClient之外,WebFlux框架还支持反应式WebSocket和相应的WebSocketClient,用于Reactive Streams的套接字样式流。

更详细的资料请阅读 working with Reactive WebSocket with Spring 5.

最后,本文的所有的源码都可以在 Github找到。