27.2 The Spring WebFlux Framework

Spring WebFlux是Spring framework 5.0中引入的新的响应式web框架。与Spring MVC不同,它不需要Servlet API,是完全异步的、非阻塞的,并通过Reactor实现了响应流规范.

Spring WebFlux有两种风格:函数式的和基于注解的.基于注解的非常接近于Spring MVC模型,如以下示例所示:

  1. @RestController
  2. @RequestMapping("/users")
  3. public class MyRestController {
  4. @GetMapping("/{user}")
  5. public Mono<User> getUser(@PathVariable Long user) {
  6. // ...
  7. }
  8. @GetMapping("/{user}/customers")
  9. public Flux<Customer> getUserCustomers(@PathVariable Long user) {
  10. // ...
  11. }
  12. @DeleteMapping("/{user}")
  13. public Mono<User> deleteUser(@PathVariable Long user) {
  14. // ...
  15. }
  16. }

“WebFlux.fn”函数变体,将路由配置从实际处理的请求中隔离,如以下示例所示:

  1. @Configuration
  2. public class RoutingConfiguration {
  3. @Bean
  4. public RouterFunction<ServerResponse> monoRouterFunction(UserHandler userHandler) {
  5. return route(GET("/{user}").and(accept(APPLICATION_JSON)), userHandler::getUser)
  6. .andRoute(GET("/{user}/customers").and(accept(APPLICATION_JSON)), userHandler::getUserCustomers)
  7. .andRoute(DELETE("/{user}").and(accept(APPLICATION_JSON)), userHandler::deleteUser);
  8. }
  9. }
  10. @Component
  11. public class UserHandler {
  12. public Mono<ServerResponse> getUser(ServerRequest request) {
  13. // ...
  14. }
  15. public Mono<ServerResponse> getUserCustomers(ServerRequest request) {
  16. // ...
  17. }
  18. public Mono<ServerResponse> deleteUser(ServerRequest request) {
  19. // ...
  20. }
  21. }

WebFlux是Spring框架的一部分,详细信息可参考文档.

Tip

你可以定义尽可能多的RouterFunction实例来模块化路由器的定义.如果需要应用优先级,可以对实例进行排序.

首先,将spring-boot-starter-webflux模块依赖添加到应用程序中.

Note

如果在应用程序中同时添加spring-boot-starter-webspring-boot-starter-webflux模块导致Spring Boot自动配置Spring MVC,而不是WebFlux. 这种行为已经被选择,因为许多Spring开发者添加spring-boot—starter-webflux依赖到他们的Spring MVC应用中以便于使用响应式WebClient. 你仍然可以执行你的选择通过配置SpringApplication.setWebApplicationType(WebApplicationType.REACTIVE)来选择应用程序类型.

Spring WebFlux Auto-configuration

Spring Boot为Spring WebFlux提供了自动配置,在大多数应用程序中运行良好.自动配置为Spring的默认配置基础上上添加以下特性:

  • 为HttpMessageReader和HttpMessage实例配置编码.
  • 静态资源处理提供支持,包括WebJars的处理.

如果你想保持Spring Boot WebFlux的特性并想要添加额外的WebFlux配置,您可以添加您自己的WbFluxConfigurer类型的@Configuration配置类,但是不用@EnableWebFlux.

如果你想要完全Spring Boot WebFlux,您可以添加您自己的@Configuration类并使用@EnableWebFlux注解.

HTTP Codecs with HttpMessageReaders and HttpMessageWriters

Spring WebFlux利用HttpMessageReaderHttpMessageWriter接口来转化HTTP请求和响应.他们通过在类路径中查找库,使用CodecConfigurer配置合理的默认值.

Spring Boot使用CodecCustomizer实例来进一步定制配置.例如,spring.jackson.*配置键应用于Jackson编解码器.

如果你需要添加或定制编解码器,你可以创建一个自定义CodecCustomizer组件,如以下示例所示:

  1. import org.springframework.boot.web.codec.CodecCustomizer;
  2. @Configuration
  3. public class MyConfiguration {
  4. @Bean
  5. public CodecCustomizer myCodecCustomizer() {
  6. return codecConfigurer -> {
  7. // ...
  8. }
  9. }
  10. }

您还可以利用Boot的自定义JSON序列化器和反序列化器.

Static Content

默认情况下,Spring Boot从类路径下的/static目录(或/public,/resources,/META-INF/resources)处理静态内容.它使用Spring WebFlux的ResourceWebHandler,因此您可以通过添加自己的WebFluxConfigurer并覆盖addResourceHandlers方法来修改行为.

默认情况下,资源被映射到/*,但是你可以通过设置spring.webflux.static-path-pattern属性来修改.例如,重新设置所有的资源映射到/resources/,如下配置:

  1. spring.webflux.static-path-pattern=/resources/**

您还可以设置spring.resources.static.locations属性来自定义静态资源路径.通过这样做将使用目录路径列表替换默认值.如果你这样做,默认的欢迎页面检测将切换到您的自定义的路径.如果有一个index.html在你的启动路径下,它是应用程序的主页.

除了前面列出的“标准”静态资源的路径,另外还可使用特例Webjars内容.在/webjars/**路径下的任何资源如果被打包成WebJars格式,那么都将以jar格式文件处理.

Tip

Spring WebFlux应用程序不严格依赖于Servlet API,所以他们不能以war文件形式部署且不能使用src/main/webapp目录.

Template Engines

除了REST web服务之外,您还可以使用Spring MVC来服务动态HTML内容.Spring MVC支持各种模板技术,包括Thymeleaf FreeMarker和jsp.

Spring Boot包括支持以下模板引擎的自动配置:

  • FreeMarker
  • Thymeleaf
  • Mustache 当你使用一个模板引擎采用默认配置时,您的模板文件将自动从src/main/resources/templates文件夹下获取.

Error Handling

Spring Boot提供WebExceptionHandler处理器,以一种合理的方式处理所有错误.它在处理顺序中的位置在WebFlux提供的处理器之前,通常被认为是最后一个. 为机器客户端,它产生具体错误信息,HTTP状态,异常消息的JSON响应.对于浏览器客户端,有一个“whitelabel”的错误视图,呈现相同的HTML格式的数据.你可以提供你自己的HTML模板来显示错误(下节具体描述).

为改变错误处理的方式,你可以实现ErrorWebExceptionHandler并注册为该类型的Bean实例.因为WebExceptionHandler比较初级,Spring Boot还提供了一个方便的AbstractErrorWebExceptionHandler类,能让你以WebFlux函数式的方式处理错误,如以下示例所示:

  1. public class CustomErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {
  2. // Define constructor here
  3. @Override
  4. protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
  5. return RouterFunctions
  6. .route(aPredicate, aHandler)
  7. .andRoute(anotherPredicate, anotherHandler);
  8. }
  9. }

为一个更完整的图片,你也可以直接继承子类DefaultErrorWebExceptionHandler并覆盖特定的方法.

Custom Error Pages

如果你想对于给定的状态代码显示自定义HTML错误页面,您可以在/error文件夹下添加文件.错误页面可以是静态HTML(也就是说,在任何的静态资源文件夹中添加)或由模板创建.文件的名称应该是确切的状态码或系列掩码.

例如,404映射到一个静态的HTML文件,你的文件夹结构如下:

  1. src/
  2. +- main/
  3. +- java/
  4. | + <source code>
  5. +- resources/
  6. +- public/
  7. +- error/
  8. | +- 404.html
  9. +- <other public assets>

使用Mustache模板映射所有5xx错误,您的文件夹结构如下:

  1. src/
  2. +- main/
  3. +- java/
  4. | + <source code>
  5. +- resources/
  6. +- templates/
  7. +- error/
  8. | +- 5xx.ftl
  9. +- <other templates>

Web Filters

Spring WebFlux提供WebFilter接口,可通过实现它过滤HTTP请求-响应交流.应用程序上下文中定义的WebFilter实例将自动过滤每一次请求响应.

在过滤器中的顺序很重要,他们可以实现Ordered接口或标注@Order注解.Spring Boot的自动配置将为你配置web过滤器.当使用它时,过滤器的顺序如下表所示:

Web Filter Order
MetricsWebFilter Ordered.HIGHEST_PRECEDENCE + 1
WebFilterChainProxy(Spring Security) -100
HttpTraceWebFilter Ordered.LOWEST_PRECEDENCE - 10