上篇文章<你的响应阻塞了没有?--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&lt;ServerResponse&gt; 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

posted on 2019-02-20 16:42  一天不进步,就是退步  阅读(4398)  评论(0编辑  收藏  举报