RoutePredicateFactory
RoutePredicateFactory 涉及到的類在 org.springframework.cloud.gateway.handler.predicate
包下。Spring Cloud Gateway 創建 Route 對象時,使用 RoutePredicateFactory 創建 Predicate 對象。Predicate 對象可以賦值給 Route.predicate 屬性,用於匹配請求對應的 Route 。
public interface RoutePredicateFactory<C> extends ShortcutConfigurable, Configurable<C> {
String PATTERN_KEY = "pattern";
// useful for javadsl
default Predicate<ServerWebExchange> apply(Consumer<C> consumer) {
C config = newConfig();
//由實現類實現的。
consumer.accept(config);
beforeApply(config);
return apply(config);
}
default AsyncPredicate<ServerWebExchange> applyAsync(Consumer<C> consumer) {
C config = newConfig();
consumer.accept(config);
beforeApply(config);
return applyAsync(config);
}
default void beforeApply(C config) {
}
Predicate<ServerWebExchange> apply(C config);
具體實現類見:Spring Cloud Gateway介紹(一),此處僅給一個實現類的源碼解析。
大部分工廠返回的Predicate爲接口GatewayPredicate的匿名實現類。
GatewayPredicate
接口GatewayPredicate繼承於Predicate<T>,增加了3個默認方法:and,or,negative,分別返回3個實現類。
public interface GatewayPredicate extends Predicate<ServerWebExchange> {
@Override
default Predicate<ServerWebExchange> and(Predicate<? super ServerWebExchange> other) {
return new AndGatewayPredicate(this, wrapIfNeeded(other));
}
@Override
default Predicate<ServerWebExchange> negate() {
return new NegateGatewayPredicate(this);
}
@Override
default Predicate<ServerWebExchange> or(Predicate<? super ServerWebExchange> other) {
return new OrGatewayPredicate(this, wrapIfNeeded(other));
}
}
AfterRoutePredicateFactory
配置:
spring:
cloud:
gateway:
routes:
# =====================================
- id: after_route
uri: http://example.org
predicates:
- After=2017-01-20T17:42:47.789-07:00[America/Denver]
源碼:
配置類:
public static class Config {
@NotNull
private ZonedDateTime datetime;
public ZonedDateTime getDatetime() {
return datetime;
}
public void setDatetime(ZonedDateTime datetime) {
this.datetime = datetime;
}
}
apply方法:
@Override
public Predicate<ServerWebExchange> apply(Config config) {
return new GatewayPredicate() {
@Override
public boolean test(ServerWebExchange serverWebExchange) {
final ZonedDateTime now = ZonedDateTime.now();
//當前時間晚於配置的時間
return now.isAfter(config.getDatetime());
}
@Override
public String toString() {
return String.format("After: %s", config.getDatetime());
}
};
}
RoutePredicateHandlerMapping
一個請求被Gateway處理過程如下(見Spring Cloud Gateway介紹(一)):
org.springframework.web.reactive.DispatcherHandler
:接收到請求,匹配 HandlerMapping ,此處會匹配到 RoutePredicateHandlerMapping 。RoutePredicateHandlerMapping
:接收到請求,匹配 Route 。FilteringWebHandler
:獲得 Route 的 GatewayFilter 數組,創建 GatewayFilterChain 處理請求。
RoutePredicateHandlerMapping
,匹配 Route ,並返回處理 Route 的 FilteringWebHandler 。
RoutePredicateHandlerMapping
繼承org.springframework.web.reactive.handler.AbstractHandlerMapping,並覆蓋了getHandlerInternal方法。
public class RoutePredicateHandlerMapping extends AbstractHandlerMapping {
private final FilteringWebHandler webHandler;
private final RouteLocator routeLocator;
private final Integer managementPort;
private final ManagementPortType managementPortType;
public RoutePredicateHandlerMapping(FilteringWebHandler webHandler,
RouteLocator routeLocator, GlobalCorsProperties globalCorsProperties,
Environment environment) {
this.webHandler = webHandler;
this.routeLocator = routeLocator;
this.managementPort = getPortProperty(environment, "management.server.");
this.managementPortType = getManagementPortType(environment);
setOrder(1);
setCorsConfigurations(globalCorsProperties.getCorsConfigurations());
}
}
@Override
protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
// don't handle requests on management port if set and different than server port
if (this.managementPortType == DIFFERENT && this.managementPort != null
&& exchange.getRequest().getURI().getPort() == this.managementPort) {
return Mono.empty();
}
exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getSimpleName());
return lookupRoute(exchange)
// .log("route-predicate-handler-mapping", Level.FINER) //name this
.flatMap((Function<Route, Mono<?>>) r -> {
exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
if (logger.isDebugEnabled()) {
logger.debug(
"Mapping [" + getExchangeDesc(exchange) + "] to " + r);
}
exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);
return Mono.just(webHandler);
}).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {
exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
if (logger.isTraceEnabled()) {
logger.trace("No RouteDefinition found for ["
+ getExchangeDesc(exchange) + "]");
}
})));
}
protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
return this.routeLocator.getRoutes()
.concatMap(route -> Mono.just(route).filterWhen(r -> {
// add the current route we are testing
exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
return r.getPredicate().apply(exchange);
})
// instead of immediately stopping main flux due to error, log and
// swallow it
.doOnError(e -> logger.error(
"Error applying predicate for route: " + route.getId(),
e))
.onErrorResume(e -> Mono.empty()))
// .defaultIfEmpty() put a static Route not found
// or .switchIfEmpty()
// .switchIfEmpty(Mono.<Route>empty().log("noroute"))
.next()
// TODO: error handling
.map(route -> {
if (logger.isDebugEnabled()) {
logger.debug("Route matched: " + route.getId());
}
validateRoute(route, exchange);
return route;
});
}
FilteringWebHandler
SimpleHandlerAdapter#handle(ServerWebExchange, Object)
調用 FilteringWebHandler#handle(ServerWebExchange)
方法,處理請求。
FilteringWebHandler 通過創建請求對應的 Route 對應的 GatewayFilterChain 進行處理。
public class FilteringWebHandler implements WebHandler {
protected static final Log logger = LogFactory.getLog(FilteringWebHandler.class);
private final List<GatewayFilter> globalFilters;
public FilteringWebHandler(List<GlobalFilter> globalFilters) {
this.globalFilters = loadFilters(globalFilters);
}
}
handle
@Override
public Mono<Void> handle(ServerWebExchange exchange) {
Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
//獲取Filters。
List<GatewayFilter> gatewayFilters = route.getFilters();
//合併所有Filters,排序。
List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
combined.addAll(gatewayFilters);
// TODO: needed or cached?
AnnotationAwareOrderComparator.sort(combined);
if (logger.isDebugEnabled()) {
logger.debug("Sorted gatewayFilterFactories: " + combined);
}
//構造Chain。
return new DefaultGatewayFilterChain(combined).filter(exchange);
}
private static class DefaultGatewayFilterChain implements GatewayFilterChain {
@Override
public Mono<Void> filter(ServerWebExchange exchange) {
return Mono.defer(() -> {
if (this.index < filters.size()) {
GatewayFilter filter = filters.get(this.index);
DefaultGatewayFilterChain chain = new DefaultGatewayFilterChain(this,
this.index + 1);
return filter.filter(exchange, chain);
}
else {
return Mono.empty(); // complete
}
});
}
}