序
本文主要研究一下spring cloud gateway的RouteLocator
RouteLocator
spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/route/RouteLocator.java
public interface RouteLocator { FluxgetRoutes();}复制代码
其有三个实现类:
- RouteDefinitionRouteLocator
- CompositeRouteLocator
- CachingRouteLocator
GatewayAutoConfiguration
spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java
@Configuration@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)@EnableConfigurationProperties@AutoConfigureBefore(HttpHandlerAutoConfiguration.class)@AutoConfigureAfter({GatewayLoadBalancerClientAutoConfiguration.class, GatewayClassPathWarningAutoConfiguration.class})@ConditionalOnClass(DispatcherHandler.class)public class GatewayAutoConfiguration { //...... @Bean public RouteLocatorBuilder routeLocatorBuilder(ConfigurableApplicationContext context) { return new RouteLocatorBuilder(context); } @Bean public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties, ListGatewayFilters, List predicates, RouteDefinitionLocator routeDefinitionLocator) { return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates, GatewayFilters, properties); } @Bean @Primary //TODO: property to disable composite? public RouteLocator cachedCompositeRouteLocator(List routeLocators) { return new CachingRouteLocator(new CompositeRouteLocator(Flux.fromIterable(routeLocators))); } @Bean public RoutePredicateHandlerMapping routePredicateHandlerMapping(FilteringWebHandler webHandler, RouteLocator routeLocator) { return new RoutePredicateHandlerMapping(webHandler, routeLocator); } @Configuration @ConditionalOnClass(Health.class) protected static class GatewayActuatorConfiguration { @Bean @ConditionalOnEnabledEndpoint public GatewayControllerEndpoint gatewayControllerEndpoint(RouteDefinitionLocator routeDefinitionLocator, List globalFilters, List GatewayFilters, RouteDefinitionWriter routeDefinitionWriter, RouteLocator routeLocator) { return new GatewayControllerEndpoint(routeDefinitionLocator, globalFilters, GatewayFilters, routeDefinitionWriter, routeLocator); } } //......}复制代码
可以看到默认创建了RouteDefinitionRouteLocator,然后又基于它创建了CompositeRouteLocator,最后由CachingRouteLocator再包装一层
RouteDefinitionRouteLocator
spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/route/RouteDefinitionRouteLocator.java
/** * {@link RouteLocator} that loads routes from a {@link RouteDefinitionLocator} * @author Spencer Gibb */public class RouteDefinitionRouteLocator implements RouteLocator, BeanFactoryAware, ApplicationEventPublisherAware { protected final Log logger = LogFactory.getLog(getClass()); private final RouteDefinitionLocator routeDefinitionLocator; private final Mappredicates = new LinkedHashMap<>(); private final Map gatewayFilterFactories = new HashMap<>(); private final GatewayProperties gatewayProperties; private final SpelExpressionParser parser = new SpelExpressionParser(); private BeanFactory beanFactory; private ApplicationEventPublisher publisher; public RouteDefinitionRouteLocator(RouteDefinitionLocator routeDefinitionLocator, List predicates, List gatewayFilterFactories, GatewayProperties gatewayProperties) { this.routeDefinitionLocator = routeDefinitionLocator; initFactories(predicates); gatewayFilterFactories.forEach(factory -> this.gatewayFilterFactories.put(factory.name(), factory)); this.gatewayProperties = gatewayProperties; } @Autowired private Validator validator; @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; } @Override public void setApplicationEventPublisher(ApplicationEventPublisher publisher) { this.publisher = publisher; } private void initFactories(List predicates) { predicates.forEach(factory -> { String key = factory.name(); if (this.predicates.containsKey(key)) { this.logger.warn("A RoutePredicateFactory named "+ key + " already exists, class: " + this.predicates.get(key) + ". It will be overwritten."); } this.predicates.put(key, factory); if (logger.isInfoEnabled()) { logger.info("Loaded RoutePredicateFactory [" + key + "]"); } }); } @Override public Flux getRoutes() { return this.routeDefinitionLocator.getRouteDefinitions() .map(this::convertToRoute) //TODO: error handling .map(route -> { if (logger.isDebugEnabled()) { logger.debug("RouteDefinition matched: " + route.getId()); } return route; }); /* TODO: trace logging if (logger.isTraceEnabled()) { logger.trace("RouteDefinition did not match: " + routeDefinition.getId()); }*/ } //......}复制代码
- 这个类名有点绕,如同注释里头说的,它是一个routeLocator,从routeDefinitionLocator获取Route信息
- 这里注入的routeDefinitionLocator是CompositeRouteDefinitionLocator,它组合了InMemoryRouteDefinitionRepository、PropertiesRouteDefinitionLocator、DiscoveryClientRouteDefinitionLocator三个RouteDefinitionLocator。
- PropertiesRouteDefinitionLocator是直接使用GatewayProperties的getRoutes()获取,其是通过spring.cloud.gateway.routes配置得来。
convertToRoute
private Route convertToRoute(RouteDefinition routeDefinition) { Predicatepredicate = combinePredicates(routeDefinition); List gatewayFilters = getFilters(routeDefinition); return Route.builder(routeDefinition) .predicate(predicate) .replaceFilters(gatewayFilters) .build(); }复制代码
RouteDefinitionRouteLocator的getRoutes方法,从routeDefinitionLocator.getRouteDefinitions(),然后使用convertToRoute方法进行转换,该方法主要用到了combinePredicates、getFilters两个方法
combinePredicates
private PredicatecombinePredicates(RouteDefinition routeDefinition) { List predicates = routeDefinition.getPredicates(); Predicate predicate = lookup(routeDefinition, predicates.get(0)); for (PredicateDefinition andPredicate : predicates.subList(1, predicates.size())) { Predicate found = lookup(routeDefinition, andPredicate); predicate = predicate.and(found); } return predicate; } private Predicate lookup(RouteDefinition route, PredicateDefinition predicate) { RoutePredicateFactory
这里利用工厂方法,根据config去apply出来Predicate 而combinePredicates主要是对找出来的predicate进行and操作
getFilters
private ListgetFilters(RouteDefinition routeDefinition) { List filters = new ArrayList<>(); //TODO: support option to apply defaults after route specific filters? if (!this.gatewayProperties.getDefaultFilters().isEmpty()) { filters.addAll(loadGatewayFilters("defaultFilters", this.gatewayProperties.getDefaultFilters())); } if (!routeDefinition.getFilters().isEmpty()) { filters.addAll(loadGatewayFilters(routeDefinition.getId(), routeDefinition.getFilters())); } AnnotationAwareOrderComparator.sort(filters); return filters; } private List loadGatewayFilters(String id, List filterDefinitions) { List filters = filterDefinitions.stream() .map(definition -> { GatewayFilterFactory factory = this.gatewayFilterFactories.get(definition.getName()); if (factory == null) { throw new IllegalArgumentException("Unable to find GatewayFilterFactory with name " + definition.getName()); } Map args = definition.getArgs(); if (logger.isDebugEnabled()) { logger.debug("RouteDefinition " + id + " applying filter " + args + " to " + definition.getName()); } Map properties = factory.shortcutType().normalize(args, factory, this.parser, this.beanFactory); Object configuration = factory.newConfig(); ConfigurationUtils.bind(configuration, properties, factory.shortcutFieldPrefix(), definition.getName(), validator); GatewayFilter gatewayFilter = factory.apply(configuration); if (this.publisher != null) { this.publisher.publishEvent(new FilterArgsEvent(this, id, properties)); } return gatewayFilter; }) .collect(Collectors.toList()); ArrayList ordered = new ArrayList<>(filters.size()); for (int i = 0; i < filters.size(); i++) { GatewayFilter gatewayFilter = filters.get(i); if (gatewayFilter instanceof Ordered) { ordered.add(gatewayFilter); } else { ordered.add(new OrderedGatewayFilter(gatewayFilter, i + 1)); } } return ordered; }复制代码
getFilters主要是利用loadGatewayFilters获取filter,返回使用AnnotationAwareOrderComparator进行排序 loadGatewayFilters也是利用工厂方法,使用GatewayFilterFactory根据config去apply出来具体的GatewayFilter实例
小结
RouteLocator接口用于获取路由信息,其有三个实现类
- RouteDefinitionRouteLocator
- CompositeRouteLocator
- CachingRouteLocator
最终使用的是CachingRouteLocator,它包装了CompositeRouteLocator,而CompositeRouteLocator则组合了RouteDefinitionRouteLocator。
RouteDefinitionRouteLocator与RouteDefinitionLocator比较容易混淆,前者是一个RouteLocator,后者是一个RouteDefinitionLocator,前者的RouteDefinitionRouteLocator主要从后者获取路由定义信息。