关注 微信公众号:【芋道源码】 有福利:
本文主要分享 RoutePredicateHandlerMapping 路由匹配 。
我们先一起来看看,一个请求是怎么被 Spring Cloud Gateway 处理的,如下图 :
org.springframework.web.reactive.DispatcherHandler
:接收到请求,匹配 HandlerMapping ,此处会匹配到 RoutePredicateHandlerMapping 。 org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping
:接收到请求,匹配 Route 。 org.springframework.cloud.gateway.handler.FilteringWebHandler
:获得 Route 的 GatewayFilter 数组,创建 GatewayFilterChain 处理请求。 第一、二步,在本文分享。第三步,在 《Spring-Cloud-Gateway 源码解析 —— 处理器 (3.3) 之 FilteringWebHandler 创建过滤器链 》 分享。
org.springframework.web.reactive.DispatcherHandler
,请求分发处理器,Spring WebFlux 的访问入口。可能大多数人对这个类都比较陌生,我们来看看他在 Spring MVC 的兄弟 DispatcherServlet 是不是就有点熟悉的感觉。
下面来看看 DispatcherHandler#handle(ServerWebExchange)
方法,代码如下 :
1: public class DispatcherHandler implements WebHandler, ApplicationContextAware{ 2: 3: @Nullable 4: private List<HandlerMapping> handlerMappings; 5: 6: @Nullable 7: private List<HandlerAdapter> handlerAdapters; 8: 9: @Override 10: public Mono<Void> handle(ServerWebExchange exchange){ 11: if (logger.isDebugEnabled()) { 12: ServerHttpRequest request = exchange.getRequest(); 13: logger.debug("Processing " + request.getMethodValue() + " request for [" + request.getURI() + "]"); 14: } 15: if (this.handlerMappings == null) { 16: return Mono.error(HANDLER_NOT_FOUND_EXCEPTION); 17: } 18: return Flux.fromIterable(this.handlerMappings) 19: .concatMap(mapping -> mapping.getHandler(exchange)) 20: .next() 21: .switchIfEmpty(Mono.error(HANDLER_NOT_FOUND_EXCEPTION)) 22: .flatMap(handler -> invokeHandler(exchange, handler)) 23: .flatMap(result -> handleResult(exchange, result)); 24: } 25: }
第 18 至 20 行 : 顺序 使用 handlerMappings
获得对应的 WebHandler 。
#concatMap(Function)
操作符的原因是考虑 handlerMappings
的顺序性,详见 《RxJava(四) concatMap操作符用法详解》 。 spring-cloud-gateway-sample
项目,此处打断点, handlerMappings
变量值如下图 : HandlerMapping#getHandler(ServerWebExchange)
获得 Handler 。在整理,RoutePredicateHandlerMapping 匹配请求对应的 Route ,并返回 FilteringWebHandler 。此时, FilteringWebHandler 还并未获得 Route 的 GatewayFilter ,创建 GatewayFilterChain 处理请求 。和本文的第一张图有点出入,该图主要描述整个请求经历的流程。 HANDLER_NOT_FOUND_EXCEPTION
。 第 22 行 :调用 #handle()
方法,执行 Handler 。代码如下 :
1: private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler){ 2: if (this.handlerAdapters != null) { 3: for (HandlerAdapter handlerAdapter : this.handlerAdapters) { 4: if (handlerAdapter.supports(handler)) { 5: return handlerAdapter.handle(exchange, handler); 6: } 7: } 8: } 9: return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler)); 10: }
spring-cloud-gateway-sample
项目,此处打断点, handlerMappings
变量值如下图 : HandlerAdapter#handle(ServerWebExchange, Object)
方法,从而执行 Handler 。在此处,我们会匹配到 SimpleHandlerAdapter 。 第 23 行 :调用 #handleResult()
方法,处理结果。SimpleHandlerAdapter 返回的是 Mono.empty()
,所以不会触发该方法。 #handleResult()
代码如下 :
1: private Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result){ 2: return getResultHandler(result).handleResult(exchange, result) 3: .onErrorResume(ex -> result.applyExceptionHandler(ex).flatMap(exceptionResult -> 4: getResultHandler(exceptionResult).handleResult(exchange, exceptionResult))); 5: }
org.springframework.web.reactive.result.SimpleHandlerAdapter
,基执行 WebHandler 的处理器适配器。
#supports(Object)
方法 ,代码如下 :
@Override public boolean supports(Object handler) { return WebHandler.class.isAssignableFrom(handler.getClass()); }
#handle(ServerWebExchange, Object)
方法 ,代码如下 :
1: @Override 2: public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler){ 3: WebHandler webHandler = (WebHandler) handler; 4: Mono<Void> mono = webHandler.handle(exchange); 5: return mono.then(Mono.empty()); 6: }
WebHandler#handle(ServerWebExchange)
方法,执行处理器。例如, WebHandler 为 FilteringWebHandler 时,获得 Route 的 GatewayFilter 数组,创建 GatewayFilterChain 处理请求 。 #then(Mongo)
),然后返回 Mono.empty()
。 org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping
,匹配 Route ,并返回处理 Route 的 FilteringWebHandler 。
RoutePredicateHandlerMapping 构造方法 ,代码如下 :
public class RoutePredicateHandlerMapping extends AbstractHandlerMapping{ private final FilteringWebHandler webHandler; private final RouteLocator routeLocator; public RoutePredicateHandlerMapping(FilteringWebHandler webHandler, RouteLocator routeLocator){ this.webHandler = webHandler; this.routeLocator = routeLocator; setOrder(1); // RequestMappingHandlerMapping 之后 } }
#setOrder(1)
的原因,Spring Cloud Gateway 的 GatewayWebfluxEndpoint 提供 HTTP API ,不需要经过网关,它通过 RequestMappingHandlerMapping 进行请求匹配处理。RequestMappingHandlerMapping 的 order = 0
,需要排在 RoutePredicateHandlerMapping 前面。所有,RoutePredicateHandlerMapping 设置 order = 1
。 #getHandlerInternal()
方法,在 DispatcherHandler#handle(ServerWebExchange)
方法的【 第 19 行 】被调用,匹配 Route ,并返回处理 Route 的 FilteringWebHandler 。代码如下 :
1: @Override 2: protected Mono<?> getHandlerInternal(ServerWebExchange exchange) { 3: // 设置 GATEWAY_HANDLER_MAPPER_ATTR 为 RoutePredicateHandlerMapping 4: exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getClass().getSimpleName()); 5: 6: return lookupRoute(exchange) // 匹配 Route 7: // .log("route-predicate-handler-mapping", Level.FINER) //name this 8: .flatMap((Function<Route, Mono<?>>) r -> { // 返回 FilteringWebHandler 9: if (logger.isDebugEnabled()) { 10: logger.debug("Mapping [" + getExchangeDesc(exchange) + "] to " + r); 11: } 12: 13: // 设置 GATEWAY_ROUTE_ATTR 为 匹配的 Route 14: exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r); 15: // 返回 16: return Mono.just(webHandler); 17: }).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> { // 匹配不到 Route 18: if (logger.isTraceEnabled()) { 19: logger.trace("No RouteDefinition found for [" + getExchangeDesc(exchange) + "]"); 20: } 21: }))); 22: }
GATEWAY_HANDLER_MAPPER_ATTR
为 RoutePredicateHandlerMapping 。 #lookupRoute(ServerWebExchange)
方法,匹配 Route 。 GATEWAY_ROUTE_ATTR
为 匹配 的 Route 。 Mono.empty()
,即不返回处理器。 这样会不会有问题 ?不会,在 DispatcherHandler#handle(ServerWebExchange)
方法的【 第 21 行 】,我们可以看到,当没有合适的 Handler ,返回 Mono.error(HANDLER_NOT_FOUND_EXCEPTION)
。 #lookupRoute(ServerWebExchange)
方法, 顺序 匹配 Route 。代码如下 :
1: protected Mono<Route> lookupRoute(ServerWebExchange exchange){ 2: return this.routeLocator.getRoutes() 3: .filter(route -> route.getPredicate().test(exchange)) 4: .next() 5: //TODO: error handling 6: .map(route -> { 7: if (logger.isDebugEnabled()) { 8: logger.debug("RouteDefinition matched: " + route.getId()); 9: } 10: validateRoute(route, exchange); 11: return route; 12: }); 13: }
RouteLocator#getRoutes()
方法,获得全部 Route ,并调用 Predicate#test(ServerWebExchange)
方法, 顺序 匹配 一个 Route。 Predicate#test(ServerWebExchange)
的方法调用发生异常时,都会导致匹配不到 Route 。 一定要注意 。 #validateRoute(Route, ServerWebExchange)
方法,校验 Route 的有效性。目前该方法是个 空方法 ,可以通过继承 RoutePredicateHandlerMapping 进行覆盖重写。 一不小心简单写了下 WebFlux 的 DispatcherHandler 的源码解析,嘿嘿嘿。
胖友,分享一波朋友圈可好!