27.2 The Spring WebFlux Framework
Spring WebFlux是Spring framework 5.0中引入的新的响应式web框架。与Spring MVC不同,它不需要Servlet API,是完全异步的、非阻塞的,并通过Reactor实现了响应流规范.
Spring WebFlux有两种风格:函数式的和基于注解的.基于注解的非常接近于Spring MVC模型,如以下示例所示:
@RestController
@RequestMapping("/users")
public class MyRestController {
@GetMapping("/{user}")
public Mono<User> getUser(@PathVariable Long user) {
// ...
}
@GetMapping("/{user}/customers")
public Flux<Customer> getUserCustomers(@PathVariable Long user) {
// ...
}
@DeleteMapping("/{user}")
public Mono<User> deleteUser(@PathVariable Long user) {
// ...
}
}
“WebFlux.fn”函数变体,将路由配置从实际处理的请求中隔离,如以下示例所示:
@Configuration
public class RoutingConfiguration {
@Bean
public RouterFunction<ServerResponse> monoRouterFunction(UserHandler userHandler) {
return route(GET("/{user}").and(accept(APPLICATION_JSON)), userHandler::getUser)
.andRoute(GET("/{user}/customers").and(accept(APPLICATION_JSON)), userHandler::getUserCustomers)
.andRoute(DELETE("/{user}").and(accept(APPLICATION_JSON)), userHandler::deleteUser);
}
}
@Component
public class UserHandler {
public Mono<ServerResponse> getUser(ServerRequest request) {
// ...
}
public Mono<ServerResponse> getUserCustomers(ServerRequest request) {
// ...
}
public Mono<ServerResponse> deleteUser(ServerRequest request) {
// ...
}
}
WebFlux是Spring框架的一部分,详细信息可参考文档.
Tip
你可以定义尽可能多的
RouterFunction
实例来模块化路由器的定义.如果需要应用优先级,可以对实例进行排序.
首先,将spring-boot-starter-webflux
模块依赖添加到应用程序中.
Note
如果在应用程序中同时添加
spring-boot-starter-web
和spring-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利用HttpMessageReader
和HttpMessageWriter
接口来转化HTTP请求和响应.他们通过在类路径中查找库,使用CodecConfigurer
配置合理的默认值.
Spring Boot使用CodecCustomizer
实例来进一步定制配置.例如,spring.jackson.*
配置键应用于Jackson编解码器.
如果你需要添加或定制编解码器,你可以创建一个自定义CodecCustomizer
组件,如以下示例所示:
import org.springframework.boot.web.codec.CodecCustomizer;
@Configuration
public class MyConfiguration {
@Bean
public CodecCustomizer myCodecCustomizer() {
return codecConfigurer -> {
// ...
}
}
}
您还可以利用Boot的自定义JSON序列化器和反序列化器.
Static Content
默认情况下,Spring Boot从类路径下的/static
目录(或/public
,/resources
,/META-INF/resources
)处理静态内容.它使用Spring WebFlux的ResourceWebHandler
,因此您可以通过添加自己的WebFluxConfigurer
并覆盖addResourceHandlers
方法来修改行为.
默认情况下,资源被映射到/*,但是你可以通过设置spring.webflux.static-path-pattern属性来修改.例如,重新设置所有的资源映射到/resources/,如下配置:
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函数式的方式处理错误,如以下示例所示:
public class CustomErrorWebExceptionHandler extends AbstractErrorWebExceptionHandler {
// Define constructor here
@Override
protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
return RouterFunctions
.route(aPredicate, aHandler)
.andRoute(anotherPredicate, anotherHandler);
}
}
为一个更完整的图片,你也可以直接继承子类DefaultErrorWebExceptionHandler
并覆盖特定的方法.
Custom Error Pages
如果你想对于给定的状态代码显示自定义HTML错误页面,您可以在/error文件夹下添加文件.错误页面可以是静态HTML(也就是说,在任何的静态资源文件夹中添加)或由模板创建.文件的名称应该是确切的状态码或系列掩码.
例如,404
映射到一个静态的HTML文件,你的文件夹结构如下:
src/
+- main/
+- java/
| + <source code>
+- resources/
+- public/
+- error/
| +- 404.html
+- <other public assets>
使用Mustache模板映射所有5xx错误,您的文件夹结构如下:
src/
+- main/
+- java/
| + <source code>
+- resources/
+- templates/
+- error/
| +- 5xx.ftl
+- <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 |