摘要: 原创出处 http://www.iocoder.cn/Spring-Cloud-Gateway/handler-route-predicate-handler-mapping/ 「芋道源码」欢迎转载,保留摘要,谢谢!
本文主要基于 Spring-Cloud-Gateway 2.0.X M4
阅读源码最好的方式,是使用 IDEA 进行调试 Spring Cloud Gateway 源码,不然会一脸懵逼。
1. 概述
本文主要分享 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 创建过滤器链 》 分享。
推荐 Spring Cloud 书籍:
请支持正版。下载盗版,等于主动编写低级 BUG 。
程序猿DD —— 《Spring Cloud微服务实战》
两书齐买,京东包邮。
2. DispatcherHandler
org.springframework.web.reactive.DispatcherHandler ,请求分发处理器,Spring WebFlux 的访问入口。可能大多数人对这个类都比较陌生,我们来看看他在 Spring MVC 的兄弟 DispatcherServlet 是不是就有点熟悉的感觉。
下面来看看 DispatcherHandler#handle(ServerWebExchange) 方法,代码如下 :
public class DispatcherHandler implements WebHandler, ApplicationContextAware {
@Nullable
private List<HandlerMapping> handlerMappings;
@Nullable
private List<HandlerAdapter> handlerAdapters;
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
if (logger.isDebugEnabled()) {
ServerHttpRequest request = exchange.getRequest();
logger.debug("Processing " + request.getMethodValue() + " request for [" + request.getURI() + "]");
}
if (this.handlerMappings == null) {
return Mono.error(HANDLER_NOT_FOUND_EXCEPTION);
}
return Flux.fromIterable(this.handlerMappings)
.concatMap(mapping -> mapping.getHandler(exchange))
.next()
.switchIfEmpty(Mono.error(HANDLER_NOT_FOUND_EXCEPTION))
.flatMap(handler -> invokeHandler(exchange, handler))
.flatMap(result -> handleResult(exchange, result));
}
}第 18 至 20 行 :顺序使用
handlerMappings获得对应的 WebHandler 。使用
#concatMap(Function)操作符的原因是考虑handlerMappings的顺序性,详见 《RxJava(四) concatMap操作符用法详解》 。使用官方
spring-cloud-gateway-sample项目,此处打断点,handlerMappings变量值如下图 :
在【第 19 行】,调用
HandlerMapping#getHandler(ServerWebExchange)获得 Handler 。在整理,RoutePredicateHandlerMapping 匹配请求对应的 Route ,并返回 FilteringWebHandler 。此时,FilteringWebHandler 还并未获得 Route 的 GatewayFilter ,创建 GatewayFilterChain 处理请求。和本文的第一张图有点出入,该图主要描述整个请求经历的流程。第 21 行 :如果匹配不到 WebHandler ,返回
HANDLER_NOT_FOUND_EXCEPTION。第 22 行 :调用
#handle()方法,执行 Handler 。代码如下 :private Mono<HandlerResult> invokeHandler(ServerWebExchange exchange, Object handler) { if (this.handlerAdapters != null) { for (HandlerAdapter handlerAdapter : this.handlerAdapters) { if (handlerAdapter.supports(handler)) { return handlerAdapter.handle(exchange, handler); } } } return Mono.error(new IllegalStateException("No HandlerAdapter: " + handler)); }使用官方
spring-cloud-gateway-sample项目,此处打断点,handlerMappings变量值如下图 :
第 2 至 8 行 :顺序匹配 HandlerAdapter ,通过调用
HandlerAdapter#handle(ServerWebExchange, Object)方法,从而执行 Handler 。在此处,我们会匹配到 SimpleHandlerAdapter 。第 9 行 :匹配不到 HandlerAdapter ,返回 IllegalStateException 。
第 23 行 :调用
#handleResult()方法,处理结果。SimpleHandlerAdapter 返回的是Mono.empty(),所以不会触发该方法。#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))); }
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) 方法,代码如下 :
@Override
public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {
WebHandler webHandler = (WebHandler) handler;
Mono<Void> mono = webHandler.handle(exchange);
return mono.then(Mono.empty());
}第 3 至 4 行 :调用
WebHandler#handle(ServerWebExchange)方法,执行处理器。例如,WebHandler 为 FilteringWebHandler 时,获得 Route 的 GatewayFilter 数组,创建 GatewayFilterChain 处理请求。第 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 之后
}
}调用
#setOrder(1)的原因,Spring Cloud Gateway 的 GatewayWebfluxEndpoint 提供 HTTP API ,不需要经过网关,它通过 RequestMappingHandlerMapping 进行请求匹配处理。RequestMappingHandlerMapping 的order = 0,需要排在 RoutePredicateHandlerMapping 前面。所有,RoutePredicateHandlerMapping 设置order = 1。
#getHandlerInternal() 方法,在 DispatcherHandler#handle(ServerWebExchange) 方法的【第 19 行】被调用,匹配 Route ,并返回处理 Route 的 FilteringWebHandler 。代码如下 :
@Override
protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
// 设置 GATEWAY_HANDLER_MAPPER_ATTR 为 RoutePredicateHandlerMapping
exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getClass().getSimpleName());
return lookupRoute(exchange) // 匹配 Route
// .log("route-predicate-handler-mapping", Level.FINER) //name this
.flatMap((Function<Route, Mono<?>>) r -> { // 返回 FilteringWebHandler
if (logger.isDebugEnabled()) {
logger.debug("Mapping [" + getExchangeDesc(exchange) + "] to " + r);
}
// 设置 GATEWAY_ROUTE_ATTR 为 匹配的 Route
exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);
// 返回
return Mono.just(webHandler);
}).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> { // 匹配不到 Route
if (logger.isTraceEnabled()) {
logger.trace("No RouteDefinition found for [" + getExchangeDesc(exchange) + "]");
}
})));
}第 4 行 :设置
GATEWAY_HANDLER_MAPPER_ATTR为 RoutePredicateHandlerMapping 。第 6 行 :调用
#lookupRoute(ServerWebExchange)方法,匹配 Route 。第 8 至 16 行 :返回 Route 的处理器 FilteringWebHandler 。
第 14 行 :设置
GATEWAY_ROUTE_ATTR为匹配的 Route 。第 16 行 :返回 FilteringWebHandler。
第 17 至 21 行 :匹配不到 Route ,返回
Mono.empty(),即不返回处理器。这样会不会有问题?不会,在DispatcherHandler#handle(ServerWebExchange)方法的【第 21 行】,我们可以看到,当没有合适的 Handler ,返回Mono.error(HANDLER_NOT_FOUND_EXCEPTION)。
#lookupRoute(ServerWebExchange) 方法,顺序匹配 Route 。代码如下 :
protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
return this.routeLocator.getRoutes()
.filter(route -> route.getPredicate().test(exchange))
.next()
//TODO: error handling
.map(route -> {
if (logger.isDebugEnabled()) {
logger.debug("RouteDefinition matched: " + route.getId());
}
validateRoute(route, exchange);
return route;
});
}第 2 至 4 行 :调用
RouteLocator#getRoutes()方法,获得全部 Route ,并调用Predicate#test(ServerWebExchange)方法,顺序匹配一个 Route。第 5 行 :未来会增加匹配过程中发生异常的处理。目前,任何一个
Predicate#test(ServerWebExchange)的方法调用发生异常时,都会导致匹配不到 Route 。一定要注意。第 6 至 11 行 :调用
#validateRoute(Route, ServerWebExchange)方法,校验 Route 的有效性。目前该方法是个空方法,可以通过继承 RoutePredicateHandlerMapping 进行覆盖重写。