006-spring cloud gateway-GatewayAutoConfiguration核心配置-GatewayProperties初始化加载Route初始化加载
Posted 木子旭
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了006-spring cloud gateway-GatewayAutoConfiguration核心配置-GatewayProperties初始化加载Route初始化加载相关的知识,希望对你有一定的参考价值。
一、GatewayProperties
1.1、在GatewayAutoConfiguration中加载
在Spring-Cloud-Gateway初始化时,同时GatewayAutoConfiguration核心配置类会被初始化加载如下 :
NettyConfiguration 底层通信netty配置
GlobalFilter (AdaptCachedBodyGlobalFilter,RouteToRequestUrlFilter,ForwardRoutingFilter,ForwardPathFilter,WebsocketRoutingFilter,WeightCalculatorWebFilter等)
FilteringWebHandler
GatewayProperties
PrefixPathGatewayFilterFactory
RoutePredicateFactory
RouteDefinitionLocator
RouteLocator
RoutePredicateHandlerMapping 查找匹配到 Route并进行处理
GatewayWebfluxEndpoint 管理网关的 HTTP API
其中在GatewayAutoConfiguration配置加载中含初始化加载GatewayProperties实例的配置:
查看GatewayAutoConfiguration源码:
@Bean public GatewayProperties gatewayProperties() { return new GatewayProperties(); }
1.2、再次查看GatewayProperties源码:
@ConfigurationProperties("spring.cloud.gateway") @Validated public class GatewayProperties { @NotNull @Valid private List<RouteDefinition> routes = new ArrayList(); private List<FilterDefinition> defaultFilters = new ArrayList(); private List<MediaType> streamingMediaTypes; public GatewayProperties() { this.streamingMediaTypes = Arrays.asList(MediaType.TEXT_EVENT_STREAM, MediaType.APPLICATION_STREAM_JSON); } public List<RouteDefinition> getRoutes() { return this.routes; } public void setRoutes(List<RouteDefinition> routes) { this.routes = routes; } public List<FilterDefinition> getDefaultFilters() { return this.defaultFilters; } public void setDefaultFilters(List<FilterDefinition> defaultFilters) { this.defaultFilters = defaultFilters; } public List<MediaType> getStreamingMediaTypes() { return this.streamingMediaTypes; } public void setStreamingMediaTypes(List<MediaType> streamingMediaTypes) { this.streamingMediaTypes = streamingMediaTypes; } public String toString() { return "GatewayProperties{routes=" + this.routes + ", defaultFilters=" + this.defaultFilters + ", streamingMediaTypes=" + this.streamingMediaTypes + \'}\'; } }
以上会被默认加载并且读取配置信息,如下配置信息:
- spring.cloud.gateway.routes:网关路由定义配置,列表形式
- spring.cloud.gateway.default-filters: 网关默认过滤器定义配置,列表形式
- spring.cloud.gateway.streamingMediaTypes:网关网络媒体类型,列表形式
spring: cloud: gateway: default-filters: - PrefixPath=/httpbin - AddResponseHeader=X-Response-Default-Foo, Default-Bar routes: - id: websocket_test uri: ws://localhost:9000 order: 9000 predicates: - Path=/echo - id: default_path_to_httpbin uri: ${test.uri} order: 10000 predicates: - Path=/**
注意:default-filters的配置PrefixPath=/httpbin字符串,可以查看FilterDefinition的构造函数,它其中构造函数包含接收一个text字符串解析字符传并创建实例信息。predicates的配置也是如此。
字符传格式:name=param1,param2,param3
public FilterDefinition(String text) { int eqIdx = text.indexOf("="); if (eqIdx <= 0) { this.setName(text); } else { this.setName(text.substring(0, eqIdx)); String[] args = StringUtils.tokenizeToStringArray(text.substring(eqIdx + 1), ","); for(int i = 0; i < args.length; ++i) { this.args.put(NameUtils.generateName(i), args[i]); } } }
二、Route初始化加载
2.1、GatewayAutoConfiguration加载RouteLocator
/** * 创建一个根据RouteDefinition转换的路由定位器 */ @Bean public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties, List<GatewayFilterFactory> GatewayFilters, List<RoutePredicateFactory> predicates, RouteDefinitionLocator routeDefinitionLocator) { return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates, GatewayFilters, properties); } /** * 创建一个缓存路由的路由定位器 * @param routeLocators * @return */ @Bean @Primary//在相同的bean中,优先使用用@Primary注解的bean. public RouteLocator cachedCompositeRouteLocator(List<RouteLocator> routeLocators) { //1.创建组合路由定位器,根据(容器)已有的路由定位器集合 //2.创建缓存功能的路由定位器 return new CachingRouteLocator(new CompositeRouteLocator(Flux.fromIterable(routeLocators))); }
路由定位器的创建流程:
1、RouteDefinitionRouteLocator 2、CompositeRouteLocator 3、CachingRouteLocator 其中 RouteDefinitionRouteLocator 是获取路由的主要地方,CompositeRouteLocator,CachingRouteLocator对路由定位器做了附加功能的包装,最终使用的是CachingRouteLocator对外提供服务
2.2、查看RouteLocator源码:
/** * 路由定位器,服务获取路由信息 * 可以通过 RouteDefinitionRouteLocator 获取 RouteDefinition ,并转换成 Route */ public interface RouteLocator { /** * 获取路由 */ Flux<Route> getRoutes(); }
查看RouteLocator实现类
2.3、缓存功能实现→CachingRouteLocator
// 路由定位器的包装类,实现了路由的本地缓存功能 public class CachingRouteLocator implements RouteLocator { //目标路由定位器 private final RouteLocator delegate; /** * 路由信息 * Flux 相当于一个 RxJava Observable, * 能够发出 0~N 个数据项,然后(可选地)completing 或 erroring。处理多个数据项作为stream */ private final Flux<Route> routes; // 本地缓存,用于缓存路由定位器获取的路由集合 private final Map<String, List> cache = new HashMap<>(); public CachingRouteLocator(RouteLocator delegate) { this.delegate = delegate; routes = CacheFlux.lookup(cache, "routes", Route.class) .onCacheMissResume(() -> this.delegate.getRoutes().sort(AnnotationAwareOrderComparator.INSTANCE)); } @Override public Flux<Route> getRoutes() { return this.routes; } // 刷新缓存 public Flux<Route> refresh() { this.cache.clear(); return this.routes; } @EventListener(RefreshRoutesEvent.class) void handleRefresh() { refresh(); } }
1、路由信息的本地缓存,通过Map<String, List> cache 缓存路由到内存中;
2、此类通过@EventListener(RefreshRoutesEvent.class)监听RefreshRoutesEvent事件实现了对缓存的动态刷新;
注:路由动态刷新,使用GatewayControllerEndpoint发布刷新事件
@RestControllerEndpoint(id = "gateway") public class GatewayControllerEndpoint implements ApplicationEventPublisherAware{ // 调用url= /gateway/refresh 刷新缓存中的路由信息 @PostMapping("/refresh") public Mono<Void> refresh() { this.publisher.publishEvent(new RefreshRoutesEvent(this)); return Mono.empty(); } }
2.4、组合功能实现→CompositeRouteLocator
//组合多个 RRouteLocator 的实现,为Route提供统一获取入口 public class CompositeRouteLocator implements RouteLocator { /** * 能够发出 0~N 个数据项(RouteLocator),然后(可选地)completing 或 erroring。处理多个数据项作为stream */ private final Flux<RouteLocator> delegates; public CompositeRouteLocator(Flux<RouteLocator> delegates) { this.delegates = delegates; } @Override public Flux<Route> getRoutes() { //this.delegates.flatMap((routeLocator)-> routeLocator.getRoutes()); return this.delegates.flatMap(RouteLocator::getRoutes); } }
此类将遍历传入的目录路由定位器集合,组合每个路由定位器获取到的路由信息
2.5、通过路由定义转换路由实现→RouteDefinitionRouteLocator
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package org.springframework.cloud.gateway.route; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.gateway.config.GatewayProperties; import org.springframework.cloud.gateway.event.FilterArgsEvent; import org.springframework.cloud.gateway.event.PredicateArgsEvent; import org.springframework.cloud.gateway.filter.FilterDefinition; import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.OrderedGatewayFilter; import org.springframework.cloud.gateway.filter.factory.GatewayFilterFactory; import org.springframework.cloud.gateway.handler.AsyncPredicate; import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition; import org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory; import org.springframework.cloud.gateway.route.Route.AsyncBuilder; import org.springframework.cloud.gateway.support.ConfigurationUtils; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.core.Ordered; import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.validation.Validator; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Flux; public class RouteDefinitionRouteLocator implements RouteLocator, BeanFactoryAware, ApplicationEventPublisherAware { protected final Log logger = LogFactory.getLog(this.getClass()); private final RouteDefinitionLocator routeDefinitionLocator; private final Map<String, RoutePredicateFactory> predicates = new LinkedHashMap(); private final Map<String, GatewayFilterFactory> gatewayFilterFactories = new HashMap(); private final GatewayProperties gatewayProperties; private final SpelExpressionParser parser = new SpelExpressionParser(); private BeanFactory beanFactory; private ApplicationEventPublisher publisher; @Autowired private Validator validator; public RouteDefinitionRouteLocator(RouteDefinitionLocator routeDefinitionLocator, List<RoutePredicateFactory> predicates, List<GatewayFilterFactory> gatewayFilterFactories, GatewayProperties gatewayProperties) { this.routeDefinitionLocator = routeDefinitionLocator; this.initFactories(predicates); gatewayFilterFactories.forEach((factory) -> { GatewayFilterFactory var10000 = (GatewayFilterFactory)this.gatewayFilterFactories.put(factory.name(), factory); }); this.gatewayProperties = gatewayProperties; } public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; } public void setApplicationEventPublisher(ApplicationEventPublisher publisher) { this.publisher = publisher; } private void initFactories(List<RoutePredicateFactory> 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 (this.logger.isInfoEnabled()) { this.logger.info("Loaded RoutePredicateFactory [" + key + "]"); } }); } public Flux<Route> getRoutes() { return this.routeDefinitionLocator.getRouteDefinitions().map(this::convertToRoute).map((route) -> { if (this.logger.isDebugEnabled()) { this.logger.debug("RouteDefinition matched: " + route.getId()); } return route; }); } private Route convertToRoute(RouteDefinition routeDefinition) { AsyncPredicate<ServerWebExchange> predicate = this.combinePredicates(routeDefinition); List<GatewayFilter> gatewayFilters = this.getFilters(routeDefinition); return ((AsyncBuilder)Route.async(routeDefinition).asyncPredicate(predicate).replaceFilters(gatewayFilters)).build(); } private List<GatewayFilter> loadGatewayFilters(String id, List<FilterDefinition> filterDefinitions) { List<GatewayFilter> filters = (List)filterDefinitions.stream().map((definition) -> { GatewayFilterFactory factory = (GatewayFilterFactory)this.gatewayFilterFactories.get(definition.getName()); if (factory == null) { throw new IllegalArgumentException("Unable to find GatewayFilterFactory with name " + definition.getName()); } else { Map<String, String> args = definition.getArgs(); if (this.logger.isDebugEnabled()) { this.logger.debug("RouteDefinition " + id + " applying filter " + args + " to " + definition.getName()); } Map<String, Object> properties = factory.shortcutType().normalize(args, factory, this.parser, this.beanFactory); Object configuration = factory.newConfig(); ConfigurationUtils.bind(configuration, properties, factory.shortcutFieldPrefix(), definition.getName(), this.validator); GatewayFilter gatewayFilter = factory.apply(configuration); if (this.publisher != null) { this.publisher.publishEvent(new FilterArgsEvent(this, id, properties)); } return gatewayFilter; } }).collect(Collectors.toList()); ArrayList<GatewayFilter> ordered = new ArrayList(filters.size()); for(int i = 0; i < filters.size(); ++i) { GatewayFilter gatewayFilter = (GatewayFilter)filters.get(i); if (gatewayFilter instanceof Ordered) { ordered.add(gatewayFilter); } else { ordered.add(new OrderedGatewayFilter(gatewayFilter, i + 1)); } } return ordered; } private List<GatewayFilter> getFilters(RouteDefinition routeDefinition) { List<GatewayFilter> filters = new ArrayList(); if (!this.gatewayProperties.getDefaultFilters().isEmpty()) { filters.addAll(this.loadGatewayFilters("defaultFilters", this.gatewayProperties.getDefaultFilters())); } if (!routeDefinition.getFilters().isEmpty()) { filters.addAll(this.loadGatewayFilters(routeDefinition.getId(), routeDefinition.getFilters())); } AnnotationAwareOrderComparator.sort(filters); return filters; } private AsyncPredicate<ServerWebExchange> combinePredicates(RouteDefinition routeDefinition) { List<PredicateDefinition> predicates = routeDefinition.getPredicates(); AsyncPredicate<ServerWebExchange> predicate = this.lookup(routeDefinition, (PredicateDefinition)predicates.get(0)); AsyncPredicate found; for(Iterator var4 = predicates.subList(1, predicates.size()).iterator(); var4.hasNext(); predicate = predicate.and(found)) { PredicateDefinition andPredicate = (PredicateDefinition)var4.next(); found = this.lookup(routeDefinition, andPredicate); } return predicate; } private AsyncPredicate<ServerWebExchange> lookup(RouteDefinition route, PredicateDefinition predicate) { RoutePredicateFactory<Object> factory = (RoutePredicateFactory)this.predicates.get(predicate.getName()); if (factory == null) { throw new IllegalArgumentException("Unable to find RoutePredicateFactory with name " + predicate.getName()); } else { Map<String, String> args = predicate.getArgs(); if (this.logger.isDebugEnabled()) { this.logger.debug("RouteDefinition " + route.getId() + " applying " + args + " to " + predicate.getName()); } Map<String, Object> properties = factory.shortcutType().normalize(args, factory, this.parser, this.beanFactory); Object config = factory.newConfig(); ConfigurationUtils.bind(config, properties, factory.shortcutFieldPrefix(), predicate.getName(), this.validator); if (this.publisher != null) { this.publisher.publishEvent(new PredicateArgsEvent(this, route.getId(), properties)); } return factory.applyAsync(config); } } }
此类的核心方法getRoutes通过传入的routeDefinitionLocator获取路由定位,并循环遍历路由定位依次转换成路由返回,
代码中可以看到getRoutes通过convertToRoute方法将路由定位转换成路由的
2.5.1、RouteDefinition转换:convertToRoute
// RouteDefinition 转换为对应的Route private Route convertToRoute(RouteDefinition routeDefinition) { //获取routeDefinition中的Predicate信息 Predicate<ServerWebExchange> predicate = combinePredicates(routeDefinition); //获取routeDefinition中的GatewayFilter信息 List<GatewayFilter> gatewayFilters = getFilters(routeDefinition); //构建路由信息 return Route.builder(routeDefinition) .predicate(predicate) .replaceFilters(gatewayFilters) .build(); }
convertToRoute方法功能作用
获取routeDefinition中的Predicate信息 (通过combinePredicates方法)
获取routeDefinition中的GatewayFilter信息(通过gatewayFilters方法)
构建路由信息
1、convertToRoute中combinePredicates获取routeDefinition中的Predicate信息如下:
// 返回组合的谓词 private Predicate<ServerWebExchange> combinePredicates(RouteDefinition routeDefinition) { //获取RouteDefinition中的PredicateDefinition集合 List<PredicateDefinition> predicates = routeDefinition.getPredicates(); Predicate<ServerWebExchange> predicate = lookup(routeDefinition, predicates.get(0)); for (PredicateDefinition andPredicate : predicates.subList(1, predicates.size())) { Predicate<ServerWebExchange> found = lookup(routeDefinition, andPredicate); //流程4 //返回一个组合的谓词,表示该谓词与另一个谓词的短路逻辑AND predicate = predicate.and(found); } return predicate; } /** * 获取一个谓语定义(PredicateDefinition)转换的谓语 * @param route * @param predicate * @return */ @SuppressWarnings("unchecked") private Predicate<ServerWebExchange> lookup(RouteDefinition route, PredicateDefinition predicate) { //流程1 //流程1==获取谓语创建工厂 RoutePredicateFactory<Object> factory = this.predicates.get(predicate.getName()); if (factory == null) { throw new IllegalArgumentException("Unable to find RoutePredicateFactory with name " + predicate.getName()); } //流程2 //获取参数 Map<String, String> args = predicate.getArgs(); if (logger.isDebugEnabled()) { logger.debug("RouteDefinition " + route.getId() + " applying " + args + " to " + predicate.getName()); } //组装参数 Map<String, Object> properties = factory.shortcutType().normalize(args, factory, this.parser, this.beanFactory); //构建创建谓语的配置信息 Object config = factory.newConfig(); ConfigurationUtils.bind(config, properties, factory.shortcutFieldPrefix(), predicate.getName(), validator); if (this.publisher != null) { this.publisher.publishEvent(new PredicateArgsEvent(this, route.getId(), properties)); } //流程3 //通过谓语工厂构建谓语 return factory.apply(config); }
获取Predicate流程:
- 根据PredicateDefinition name 获取 RoutePredicateFactory
- 根据PredicateDefinition args 组装 config信息
- 通过RoutePredicateFactory 根据config信息创建Predicate信息
- 多个Predicate 以短路逻辑AND组合
private List<GatewayFilter> getFilters(RouteDefinition routeDefinition) { List<GatewayFilter> filters = new ArrayList<>(); //校验gatewayProperties是否含义默认的过滤器集合 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; } /** * 加载过滤器,根据过滤器的定义加载 * @param id * @param filterDefinitions * @return */ @SuppressWarnings("unchecked") private List<GatewayFilter> loadGatewayFilters(String id, List<FilterDefinition> filterDefinitions) { //遍历过滤器定义,将过滤器定义转换成对应的过滤器 List<GatewayFilter> filters = filterDefinitions.stream() .map(definition -> { //流程1 //通过过滤器定义名称获取过滤器创建工厂 GatewayFilterFactory factory = this.gatewayFilterFactories.get(definition.getName()); if (factory == null) { throw new IllegalArgumentException("Unable to find GatewayFilterFactory with name " + definition.getName()); } //流程2 //获取参数 Map<String, String> args = definition.getArgs(); if (logger.isDebugEnabled()) { logger.debug("RouteDefinition " + id + " applying filter " + args + " to " + definition.getName()); } //根据args组装配置信息 Map<String, Object> properties = factory.shortcutType().normalize(args, factory, this.parser, this.beanFactory); //构建过滤器创建配置信息 Object configuration = factory.newConfig(); ConfigurationUtils.bind(configuration, properties, factory.shortcutFieldPrefix(), definition.getName(), validator); //流程3 //通过过滤器工厂创建GatewayFilter GatewayFilter gatewayFilter = factory.apply(configuration); if (this.publisher != null) { //发布事件 this.publisher.publishEvent(new FilterArgsEvent(this, id, properties)); } return gatewayFilter; }) .collect(Collectors.toList()); ArrayList<GatewayFilter> ordered = new ArrayList<>(filters.size()); //包装过滤器使其所有过滤器继承Ordered属性,可进行排序 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 方法 同时加载 全局配置 gatewayProperties与routeDefinition配置下的所有过滤器定义filterDefinitions
- loadGatewayFilters 负责将filterDefinition转化成对应的GatewayFilter
转化流程如下
- 根据filterDefinition name 获取 GatewayFilterFactory
- 根据filterDefinition args 组装 config信息
- 通过GatewayFilterFactory 根据config信息创建PGatewayFilter信息
以上是关于006-spring cloud gateway-GatewayAutoConfiguration核心配置-GatewayProperties初始化加载Route初始化加载的主要内容,如果未能解决你的问题,请参考以下文章