spring boot整合spring5-webflux从0开始的实战及源码解析
上篇文章<你的響應阻塞了沒有?--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 {@Beanpublic 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
@Overridepublic 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?
@Overridepublic 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方法
@Overridepublic 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來處理結果
@Overridepublic 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() {@Overridepublic List<HttpMessageWriter<?>> messageWriters() {return messageWriters;}@Overridepublic 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
總結
以上是生活随笔為你收集整理的spring boot整合spring5-webflux从0开始的实战及源码解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 从初创公司的角度来看微服务
- 下一篇: 从0开始构建你的api网关--Sprin