How Spring Cloud Gateway Initializes Predicates and Routes Internally
This article explains how Spring Cloud Gateway (Hoxton.SR11) creates and configures predicate factories, binds their Config objects, builds Route objects, caches them with CachingRouteLocator, and finally matches incoming requests to the appropriate route using asynchronous predicates.
Environment
Spring Cloud Gateway version Hoxton.SR11.
Predicate factories and configuration
All predicate factories follow the naming pattern XxxRoutePredicateFactory and extend AbstractRoutePredicateFactory<Config> . Each factory’s inner Config class receives values from the application’s YAML configuration.
<code>public class MethodRoutePredicateFactory extends AbstractRoutePredicateFactory<MethodRoutePredicateFactory.Config> { }</code> <code>public class PathRoutePredicateFactory extends AbstractRoutePredicateFactory<PathRoutePredicateFactory.Config> { }</code>6.1 Gateway auto‑configuration
The GatewayAutoConfiguration class declares beans for all predicate factories and the main RouteLocator implementation.
<code>public class GatewayAutoConfiguration {<br> @Bean @ConditionalOnEnabledPredicate<br> public PathRoutePredicateFactory pathRoutePredicateFactory() { return new PathRoutePredicateFactory(); }<br> @Bean @ConditionalOnEnabledPredicate<br> public QueryRoutePredicateFactory queryRoutePredicateFactory() { return new QueryRoutePredicateFactory(); }<br> @Bean<br> public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties, List<GatewayFilterFactory> gatewayFilters, List<RoutePredicateFactory> predicates, RouteDefinitionLocator routeDefinitionLocator, ConfigurationService configurationService) {<br> return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates, gatewayFilters, properties, configurationService);<br> }<br> @Bean @Primary @ConditionalOnMissingBean(name = "cachedCompositeRouteLocator")<br> public RouteLocator cachedCompositeRouteLocator(List<RouteLocator> routeLocators) {<br> return new CachingRouteLocator(new CompositeRouteLocator(Flux.fromIterable(routeLocators)));<br> }<br>}</code>CachingRouteLocator caches the routes produced by RouteDefinitionRouteLocator after the application context starts.
<code>public class CachingRouteLocator implements RouteLocator {<br> private final RouteLocator delegate;<br> private final Flux<Route> routes;<br> private final Map<String, List> cache = new ConcurrentHashMap<>();<br> public CachingRouteLocator(RouteLocator delegate) {<br> this.delegate = delegate;<br> this.routes = CacheFlux.lookup(cache, CACHE_KEY, Route.class).onCacheMissResume(this::fetch);<br> }<br> private Flux<Route> fetch() { return delegate.getRoutes().sort(AnnotationAwareOrderComparator.INSTANCE); }<br>}</code>Initializing predicate factories
RouteDefinitionRouteLocator registers each RoutePredicateFactory by its normalized name.
<code>private void initFactories(List<RoutePredicateFactory> predicates) {<br> predicates.forEach(factory -> {<br> String key = factory.name();<br> if (this.predicates.containsKey(key)) {<br> logger.warn("A RoutePredicateFactory named " + key + " already exists, it will be overwritten.");<br> }<br> this.predicates.put(key, factory);<br> });<br>}</code>The default name() method returns NameUtils.normalizeRoutePredicateName(getClass()) .
<code>default String name() { return NameUtils.normalizeRoutePredicateName(getClass()); }</code>Combining predicates and building a Route
The flow is getRoutes → convertToRoute → combinePredicates → lookup . Each predicate definition is looked up, its configuration bound, and then combined with logical and operations.
<code>private AsyncPredicate<ServerWebExchange> combinePredicates(RouteDefinition routeDefinition) {<br> for (PredicateDefinition andPredicate : predicates.subList(1, predicates.size())) {<br> AsyncPredicate<ServerWebExchange> found = lookup(routeDefinition, andPredicate);<br> predicate = predicate.and(found);<br> }<br> return predicate;<br>}</code> <code>private AsyncPredicate<ServerWebExchange> lookup(RouteDefinition route, PredicateDefinition predicate) {<br> RoutePredicateFactory<Object> factory = this.predicates.get(predicate.getName());<br> if (factory == null) { throw new IllegalArgumentException("Unable to find RoutePredicateFactory with name " + predicate.getName()); }<br> Object config = configurationService.with(factory)<br> .name(predicate.getName())<br> .properties(predicate.getArgs())<br> .eventFunction((bound, properties) -> new PredicateArgsEvent(this, route.getId(), properties))<br> .bind();<br> return factory.applyAsync(config);<br>}</code>The applyAsync method converts the factory’s synchronous apply result to an AsyncPredicate :
<code>default AsyncPredicate<ServerWebExchange> applyAsync(C config) { return toAsyncPredicate(apply(config)); }</code>Route object
<code>public class Route implements Ordered {<br> private final String id;<br> private final URI uri;<br> private final int order;<br> private final AsyncPredicate<ServerWebExchange> predicate;<br> private final List<GatewayFilter> gatewayFilters;<br> private final Map<String, Object> metadata;<br>}</code>All created Route instances are stored in CachingRouteLocator.routes .
Route locating at request time
RoutePredicateHandlerMapping (similar to Spring MVC’s HandlerMapping ) uses the primary CachingRouteLocator to iterate over cached routes, applying each route’s predicate to the incoming ServerWebExchange until a match is found.
<code>protected Mono<Route> lookupRoute(ServerWebExchange exchange) {<br> return this.routeLocator.getRoutes()<br> .concatMap(route -> Mono.just(route).filterWhen(r -> {<br> exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());<br> return r.getPredicate().apply(exchange);<br> }))<br> .next()<br> .map(route -> { validateRoute(route, exchange); return route; });<br>}</code>The matched route’s GatewayPredicate.test finally determines whether the request satisfies the configured predicates.
Overall process
The framework initializes all predicate factories and filter factories at startup.
Configuration (YAML) is bound to each factory’s Config object, and a Route instance is created with combined predicates and filters.
When a request arrives, RoutePredicateHandlerMapping scans the cached routes, applies their asynchronous predicates, and selects the first matching route.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.