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”函数变体,将路由配置从实际处理的请求中隔离,如以下示例所示:
@Configurationpublic class RoutingConfiguration {@Beanpublic 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);}}@Componentpublic 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;@Configurationpublic class MyConfiguration {@Beanpublic 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@Overrideprotected 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 |
