上篇文章 <你的响应阻塞了没有?--Spring-webFlux 源码分析> 介绍了 spring5.0 新出来的异步非阻塞服务, 很多读者说太理论了, 太单调了, 这次我们就通过一个从 0 开始的实例实战一下.
1. 准备工作
spring 提供的 IDE 工 STS, 配置好 maven 即可
2. 创建 spring boot start 项目 spring5-webflux, 并添加依赖
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-parent</artifactId>
- <version>2.1.3.RELEASE</version>
- <relativePath/> <!-- lookup parent from repository -->
- </parent>
- <groupId>com.example</groupId>
- <artifactId>spring5-webflux</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <name>spring5-webflux</name>
- <description>Demo project for Spring Boot</description>
- <properties>
- <java.version>1.8</java.version>
- </properties>
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-webflux</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- </dependency>
- </dependencies>
- <build>
- <plugins>
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- </plugin>
- </plugins>
- </build>
- </project>
3. 增加处理器 HelloWorldHandler
- package com.example.demo;
- import org.springframework.http.MediaType;
- import org.springframework.stereotype.Component;
- import org.springframework.Web.reactive.function.BodyInserters;
- import org.springframework.Web.reactive.function.server.ServerRequest;
- import org.springframework.Web.reactive.function.server.ServerResponse;
- import reactor.core.publisher.Mono;
- @Component
- public class HelloWorldHandler {
- public Mono<ServerResponse> helloWorld(ServerRequest request) {
- return ServerResponse.ok().contentType(MediaType.TEXT_PLAIN)
- .body(BodyInserters.fromObject("Hello World!"));
- }
- }
4. 增加路由器, 对应 HandlerFunction
- package com.example.demo;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.http.MediaType;
- import org.springframework.Web.reactive.function.server.RequestPredicates;
- import org.springframework.Web.reactive.function.server.RouterFunction;
- import org.springframework.Web.reactive.function.server.RouterFunctions;
- import org.springframework.Web.reactive.function.server.ServerResponse;
- @Configuration
- public class HelloWorldRouter {
- @Bean
- public RouterFunction<ServerResponse> routeHelloWorld(HelloWorldHandler helloWorldHandler) {
- return RouterFunctions
- .route(RequestPredicates.GET("/helloWorld").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)), helloWorldHandler::helloWorld);
- }
- }
默认启动时, 提供了 DefaultRouterFunction 的实例
- /**
- * Route to the given handler function if the given request predicate applies.
- * <p>For instance, the following example routes GET requests for "/user" to the
- * {@code listUsers} method in {@code userController}:
- * <pre class="code">
- * RouterFunction<ServerResponse> route =
- * RouterFunctions.route(RequestPredicates.GET("/user"), userController::listUsers);
- * </pre>
- * @param predicate the predicate to test
- * @param handlerFunction the handler function to route to if the predicate applies
- * @param <T> the type of response returned by the handler function
- * @return a router function that routes to {@code handlerFunction} if
- * {@code predicate} evaluates to {@code true}
- * @see RequestPredicates
- */
- public static <T extends ServerResponse> RouterFunction<T> route(
- RequestPredicate predicate, HandlerFunction<T> handlerFunction) {
- return new DefaultRouterFunction<>(predicate, handlerFunction);
- }
5. 启动 spring boot 项目, 调试进入 DispatchHandler
- @Override
- public Mono<Void> handle(ServerWebExchange exchange) {
- if (this.handlerMappings == null) {
- return createNotFoundError();
- }
- return Flux.fromIterable(this.handlerMappings)
- .concatMap(mapping -> mapping.getHandler(exchange))
- .next()
- .switchIfEmpty(createNotFoundError())
- .flatMap(handler -> invokeHandler(exchange, handler))
- .flatMap(result -> handleResult(exchange, result));
- }
此时 HandlerMapping 已经初始化完成
5.1 获取 Handler
AbstractHandlerMapping.java
- @Override
- public Mono<Object> getHandler(ServerWebExchange exchange) {
- return getHandlerInternal(exchange).map(handler -> {
- if (logger.isDebugEnabled()) {
- logger.debug(exchange.getLogPrefix() + "Mapped to" + handler);
- }
- if (CorsUtils.isCorsRequest(exchange.getRequest())) {
- CorsConfiguration configA = this.corsConfigurationSource.getCorsConfiguration(exchange);
- CorsConfiguration configB = getCorsConfiguration(handler, exchange);
- CorsConfiguration config = (configA != null ? configA.combine(configB) : configB);
- if (!getCorsProcessor().process(config, exchange) ||
- CorsUtils.isPreFlightRequest(exchange.getRequest())) {
- return REQUEST_HANDLED_HANDLER;
- }
- }
- return handler;
- });
- }
通过 RouterFunctions 获取 HandlerAdapter
5.2 执行 HandlerAdapter
HelloWorldHandler 的类型是 HandlerFunctionAdapter 类型, 触发 HandlerFunctionAdapter 执行 handle 方法
- @Override
- public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {
- HandlerFunction<?> handlerFunction = (HandlerFunction<?>) handler;
- ServerRequest request = exchange.getRequiredAttribute(RouterFunctions.REQUEST_ATTRIBUTE);
- return handlerFunction.handle(request)
- .map(response -> new HandlerResult(handlerFunction, response, HANDLER_FUNCTION_RETURN_TYPE));
- }
最后调用 HelloWorldHandler 的 helloWorld 方法
- @Component
- public class HelloWorldHandler {
- public Mono<ServerResponse> helloWorld(ServerRequest request) {
- return ServerResponse.ok().contentType(MediaType.TEXT_PLAIN)
- .body(BodyInserters.fromObject("Hello World!"));
- }
- }
5.3 执行 HandleResult
- private Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
- return getResultHandler(result).handleResult(exchange, result)
- .onErrorResume(ex -> result.applyExceptionHandler(ex).flatMap(exceptionResult ->
- getResultHandler(exceptionResult).handleResult(exchange, exceptionResult)));
- }
因 HelloWorldRouter 返回结果类型是 ServerResponse, 故调用 ServerResponseResultHandler 来处理结果
- @Override
- public Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
- ServerResponse response = (ServerResponse) result.getReturnValue();
- Assert.state(response != null, "No ServerResponse");
- return response.writeTo(exchange, new ServerResponse.Context() {
- @Override
- public List<HttpMessageWriter<?>> messageWriters() {
- return messageWriters;
- }
- @Override
- public List<ViewResolver> viewResolvers() {
- return viewResolvers;
- }
- });
- }
6. 总结
spring mvc 和 spring webflux 是一对兄弟, 他们的处理流程类似, mvc 是同步阻塞服务, webflux 是异步非阻塞服务, 它们直接的关系如下:
spring webflux 增加了 functional endpoint,RouterFunction(RouterFunctions 构建)等同于 HanderMapping, HandlerFunction(HandlerFunctionAdapter 继承自 HandlerAdapter 来代理)等同于 HandlerAdapter
spring webflux 引入了 spring boot2,Reactor,lambda 表达式, 语法更简洁, 但可读性变弱.
参考文献:
[1] https://www.journaldev.com/20763/spring-webflux-reactive-programming
来源: https://www.cnblogs.com/davidwang456/p/10407557.html