1. 概述
本文主要分享 RoutePredicateHandlerMapping 路由比對。
我們先一起來看看,一個請求是怎麼被 Spring Cloud Gateway 處理的,如下圖 :

-
:接收到請求,比對 HandlerMapping ,此處會比對到 RoutePredicateHandlerMapping 。org.springframework.web.reactive.DispatcherHandler
-
:接收到請求,比對 Route 。org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping
-
:獲得 Route 的 GatewayFilter 數組,建立 GatewayFilterChain 處理請求。org.springframework.cloud.gateway.handler.FilteringWebHandler
第一、二步,在本文分享。第三步,在 《Spring-Cloud-Gateway 源碼解析 —— 處理器 (3.3) 之 FilteringWebHandler 建立過濾器鍊 》 分享。
2. DispatcherHandler
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)
的順序性,詳見 《RxJava(四) concatMap操作符用法詳解》 。handlerMappings
- 使用官方
項目,此處打斷點,spring-cloud-gateway-sample
變量值如下圖 :handlerMappings
Spring-Cloud-Gateway 源碼解析 —— 處理器 (3.2) 之 RoutePredicateHandlerMapping 路由比對1. 概述2. DispatcherHandler3. RoutePredicateHandlerMapping - 在【第 19 行】,調用
獲得 Handler 。在整理,RoutePredicateHandlerMapping 比對請求對應的 Route ,并傳回 FilteringWebHandler 。此時,FilteringWebHandler 還并未獲得 Route 的 GatewayFilter ,建立 GatewayFilterChain 處理請求。和本文的第一張圖有點出入,該圖主要描述整個請求經曆的流程。HandlerMapping#getHandler(ServerWebExchange)
- 第 21 行 :如果比對不到 WebHandler ,傳回
。HANDLER_NOT_FOUND_EXCEPTION
- 第 22 行 :調用
方法,執行 Handler 。代碼如下 :#handle()
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
Spring-Cloud-Gateway 源碼解析 —— 處理器 (3.2) 之 RoutePredicateHandlerMapping 路由比對1. 概述2. DispatcherHandler3. RoutePredicateHandlerMapping - 第 2 至 8 行 :順序比對 HandlerAdapter ,通過調用
方法,進而執行 Handler 。在此處,我們會比對到 SimpleHandlerAdapter 。HandlerAdapter#handle(ServerWebExchange, Object)
- 第 9 行 :比對不到 HandlerAdapter ,傳回 IllegalStateException 。
- 使用官方
- 第 23 行 :調用
方法,處理結果。SimpleHandlerAdapter 傳回的是#handleResult()
,是以不會觸發該方法。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: }
2.1 SimpleHandlerAdapter
org.springframework.web.reactive.result.SimpleHandlerAdapter
,基執行 WebHandler 的處理器擴充卡。
#supports(Object)
方法,代碼如下 :
@Override
public boolean supports(Object handler) {
return WebHandler.class.isAssignableFrom(handler.getClass());
}
- 支援 WebHandler 。
#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: }
- 第 3 至 4 行 :調用
方法,執行處理器。例如,WebHandler 為 FilteringWebHandler 時,獲得 Route 的 GatewayFilter 數組,建立 GatewayFilterChain 處理請求。WebHandler#handle(ServerWebExchange)
- 第 5 行 :在 WebHandler 執行完後 (
),然後傳回#then(Mongo)
。Mono.empty()
3. RoutePredicateHandlerMapping
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 之後
}
}
- 調用
的原因,Spring Cloud Gateway 的 GatewayWebfluxEndpoint 提供 HTTP API ,不需要經過網關,它通過 RequestMappingHandlerMapping 進行請求比對處理。RequestMappingHandlerMapping 的#setOrder(1)
,需要排在 RoutePredicateHandlerMapping 前面。所有,RoutePredicateHandlerMapping 設定order = 0
。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: }
- 第 4 行 :設定
為 RoutePredicateHandlerMapping 。GATEWAY_HANDLER_MAPPER_ATTR
- 第 6 行 :調用
方法,比對 Route 。#lookupRoute(ServerWebExchange)
- 第 8 至 16 行 :傳回 Route 的處理器 FilteringWebHandler 。
- 第 14 行 :設定
為比對的 Route 。GATEWAY_ROUTE_ATTR
- 第 16 行 :傳回 FilteringWebHandler。
- 第 14 行 :設定
- 第 17 至 21 行 :比對不到 Route ,傳回
,即不傳回處理器。這樣會不會有問題?不會,在Mono.empty()
方法的【第 21 行】,我們可以看到,當沒有合适的 Handler ,傳回DispatcherHandler#handle(ServerWebExchange)
。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: }
- 第 2 至 4 行 :調用
方法,獲得全部 Route ,并調用RouteLocator#getRoutes()
方法,順序比對一個 Route。Predicate#test(ServerWebExchange)
- 第 5 行 :未來會增加比對過程中發生異常的處理。目前,任何一個
的方法調用發生異常時,都會導緻比對不到 Route 。一定要注意。Predicate#test(ServerWebExchange)
- 第 6 至 11 行 :調用
方法,校驗 Route 的有效性。目前該方法是個空方法,可以通過繼承 RoutePredicateHandlerMapping 進行覆寫重寫。#validateRoute(Route, ServerWebExchange)