SpringBootWebFlux2.1.7中⽂翻译⽂档
1. 前⾔
从⼀开始学习 Netty 到 rxjava、Rector,再到 java8 的 CompletableFuture,就深深的为响应式编程着迷,这种区别于传统的顺序式编程,没准未来能在编程世界开辟⼀⽚天地呢!
然后接触到了 WebFlux 框架,也是充满了浓厚的兴趣,想好好琢磨⼀番,奈何中⽂资料实在太少,就打起了英⽂⽂档的主意,可惜英⽂⽔平实在捉急,总是看下⼀句,忘了上⼀句。诶,要不咱⼀句句翻译出来吧,这样读起来就通顺了,顺便可以造福下后来学习者(想着翻译的东西要被⼈看,也是⼀份坚持的动⼒)。
翻译并没有逐字逐句去纠结,⼒求语义通顺,有理解错误的地⽅,还⿇烦⼤家指出,⼀起学习探讨。另外,⽂中还补充了⼀些⾃⼰练习的 demo。tips:翻译是⼀项提⾼英语和学习技能⼀举两得的事呀!
2. WebFlux 简介
Spring WebFlux 是 Spring 5.0 引⼊的新的响应式框架,区别于 Spring MVC,它不需要依赖Servlet API,它是完全异步⾮阻塞的,并且基于 Reactor 来实现响应式流规范。
Spring WebFlux 有两种表现形式:基于配置和基于注释。基于注释的实现⽅式⾮常类似于 SpringMVC 模型,如以下实例:
@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) {
// ...
}
}
基于配置的实现⽅式,把路由和具体请求逻辑分离开,如以下实例:
@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 框架的⼀部分,其中提供了详细信息。
你可以定义任意数量的 RouterFunction Bean,以对你的路由进⾏归纳整理。当然,你也可以针对多个 RouterFunction 设置优先级(@Order 注解)。
开始⼀个 WebFlux 项⽬,⾸先,需要将 spring-boot-starter-webflux 模块引⼊你的项⽬。值得注意的是,如果你同时引⼊了 spring-boot-starter-web 和spring-boot-starter-webflux 模块会导致 Spring Boot ⾃动配置Spring MVC,⽽不是 WebFlux。因为许多 Spring 开发⼈员引⼊ spring-boot-starter-webflux ,
仅仅是为了使⽤它的响应式编程(这个理由也是绝了),当然你也可以强制把你的项⽬配置成 WebFlux:
SpringApplication.setWebApplicationType(WebApplicationType.REACTIVE)
3. ⾃动配置
Spring Boot 为 Spring WebFlux 提供的⾃动配置基本能适⽤于⼤多数应⽤。
Spring Boot 的提供的⾃动配置主要做了以下两个⼯作:
为 HttpMessageReader 和 HttpMessageWriter 实例配置 HTTP 编解码器
⽀持服务静态资源映射,包括对 WebJars 资源的⽀持
如果你想要保持 Spring Boot WebFlux 的⾃动配置功能,并且想添加额外的 WebFlux 配置项,你可以⾃定义 @Configuration 配置类,但不要添加
@EnableWebFlux 注解。springboot中文
如果你想要完全控制 WebFlux,你可以定义@Configuration 配置类,并且添加 @EnableWebFlux. 注
解。
4. HttpMessageReaders 和 HttpMessageWriters 的 HTTP 编解码器
Spring WebFlux 使⽤ HttpMessageReader 和 HttpMessageWriter 接⼝来转换 HTTP 请求和响应,可以通过 CodecConfigurer 得到它们的默认配置:public interface CodecConfigurer {
...
List<HttpMessageReader<?>> getReaders();
List<HttpMessageWriter<?>> getWriters();
...
}
Spring Boot 提供了 CodecCustomizer 接⼝,允许你进⼀步定制编解码器,通过其 customize() ⽅法可以获取到 CodecConfigurer 对象,从⽽可以注册新的编解码⼯具,或对现有的编解码⼯具进⾏替换等。如以下实例:
import org.springframework.dec.CodecCustomizer;
@Configuration
public class MyConfiguration {
@Bean
public CodecCustomizer myCodecCustomizer() {
return codecConfigurer -> {
// ...
}
}
}
5. 静态资源
Spring Boot 默认从类路径的以下⽬录(/static、 /public 、/resources 、/META-INF/resources)加载静态资源,当然,你可以⾃定义配置类实现WebFluxConfigurer 并重写 addResourceHandlers ⽅法来修改默认资源路径:
@Configuration
public class MyWebFluxConfigurer implements WebFluxConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// do more
}
}
Spring Boot 默认将静态资源映射在 /** 的路径下,当然,你可以通过修改 spring.webflux.static-path-pattern 属性来调整默认映射,例如,将所有资源映射到 /resources/** 路径,可以通过以下⽅式实现:
spring.webflux.static-path-pattern=/resources/**
你也可以通过设置 sources.static-locations 属性值来⾃定义资源⽬录,如果你这样做了,默认的欢迎页⾯检测也将会切换到你设置的资源⽬录。因此,在你的资源⽬录中,只要有⼀个 index.html 页⾯,都将会成为你的应⽤主页。
除了前⾯介绍的标准静态资源外,还有⼀种特殊的情况,那就是 webjars 内容。如果静态资源被打包成了 webjars 的格式,那么访问这些资源的路径就变成了 /webjars/** 。
tips:Spring WebFlux 应⽤程序不严格依赖 Servlet API,因此不能将它们部署为 war ⽂件,也不使⽤ src/main/webapp ⽬录。
6. 模板引擎
Spring WebFlux 除了提供 REST web 服务外,还⽀持渲染动态 HTML 内容,Spring WebFlux ⽀持⼀系列模板引擎,包括 Thymeleaf、FreeMarker 和Mustache。
Spring Boot 为以下的模板引擎提供了⾃动配置的⽀持:
当你使⽤了其中某个模板引擎,并选择了 Spring Boot ⾃动配置,你需要将你的模板⽂件放在 src/main/resources/templates ⽬录下,以便被 Spring Boot 发现。
7. 异常处理
Spring Boot 提供了⼀个 WebExceptionHandler ⽤来处理所有错误,WebExceptionHandler 执⾏通常被认为是处理链中的最后⼀步,仅位于 WebFlux 提供服务之前。对于机器端,它通常是⼀个 JSON 响应,包含了HTTP 状态码、错误信息等;对于浏览器端,它通常是⼀个 “whitelabel” HTML 错误页⾯,页⾯渲染了相同的错误信息。当然,你也可以提供⾃定义的 HTML 模板来展⽰错误信息(下⽂会说到)。
⾸先,定制此功能通常涉及利⽤现有机制,但要替换或增加错误内容,你可以添加 ErrorAttributes 类型的 Bean。
若要更改错误处理⾏为,可以实现 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);
}
}
如果你想要为给定的错误码展⽰⾃定义的 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.mustache
+- <other templates>
8. 过滤器
Spring WebFlux 提供了⼀个 WebFilter 接⼝,⽤来对 HTTP 请求-响应路由进⾏过滤,在应⽤程序上下⽂中到的 WebFilter bean 将⾃动⽤于过滤每个路由!以下是⼀个简单鉴权的过滤器 demo — 对于没有 token 参数的请求返回 401 错误:
@Component
public class CustomWebFilter implements WebFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
ServerHttpRequest request = Request();
MultiValueMap<String, String> queryParams = QueryParams();
if (queryParams == null || StringUtils.First("token"))) {
Map<String, String> resultMap = new HashMap<>();
resultMap.put("code", "401");
resultMap.put("msg", "⾮法请求");
byte[] datas = new byte[0];
try {
datas = new ObjectMapper().writeValueAsBytes(resultMap);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
ServerHttpResponse response = Response();
DataBuffer buffer = response.bufferFactory().wrap(datas);
response.setStatusCode(HttpStatus.UNAUTHORIZED);
return response.writeWith(Mono.just(buffer));
}
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
ServerHttpResponse response = Response();
//Manipulate the response in some way
}));
}
}
可以通过实现 Ordered 接⼝或使⽤ @Order 注释来设置过滤器的执⾏顺序(执⾏顺序是从⼩到⼤执⾏,较⾼的值被解释为较低的优先级)。Spring Boot 的⾃动配置功能已经为你提供了⼀些内置的过滤器,如下是它们的执⾏顺序:
Web Filter Order
MetricsWebFilter Ordered.HIGHEST_PRECEDENCE + 1
WebFilterChainProxy (Spring Security)-100
HttpTraceWebFilter Ordered.LOWEST_PRECEDENCE - 10
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论