一、GatewayProperties
1.1、在GatewayAutoConfiguration中加载
在Spring-Cloud-Gateway初始化时,同时GatewayAutoConfiguration核心配置类会被初始化加载如下 :
NettyConfiguration 底层通信netty配置GlobalFilter (AdaptCachedBodyGlobalFilter,RouteToRequestUrlFilter,ForwardRoutingFilter,ForwardPathFilter,WebsocketRoutingFilter,WeightCalculatorWebFilter等)FilteringWebHandlerGatewayPropertiesPrefixPathGatewayFilterFactoryRoutePredicateFactoryRouteDefinitionLocatorRouteLocatorRoutePredicateHandlerMapping 查找匹配到 Route并进行处理GatewayWebfluxEndpoint 管理网关的 HTTP API
其中在GatewayAutoConfiguration配置加载中含初始化加载GatewayProperties实例的配置:
查看GatewayAutoConfiguration源码:
@Bean public GatewayProperties gatewayProperties() { return new GatewayProperties(); }
1.2、再次查看GatewayProperties源码:
@ConfigurationProperties("spring.cloud.gateway")@Validatedpublic class GatewayProperties { @NotNull @Valid private Listroutes = new ArrayList(); private List defaultFilters = new ArrayList(); private List streamingMediaTypes; public GatewayProperties() { this.streamingMediaTypes = Arrays.asList(MediaType.TEXT_EVENT_STREAM, MediaType.APPLICATION_STREAM_JSON); } public List getRoutes() { return this.routes; } public void setRoutes(List routes) { this.routes = routes; } public List getDefaultFilters() { return this.defaultFilters; } public void setDefaultFilters(List defaultFilters) { this.defaultFilters = defaultFilters; } public List getStreamingMediaTypes() { return this.streamingMediaTypes; } public void setStreamingMediaTypes(List 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
在Spring-Cloud-Gateway初始化时,同时GatewayAutoConfiguration核心配置类会被初始化加载如下 :
/** * 创建一个根据RouteDefinition转换的路由定位器 */ @Bean public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties, ListGatewayFilters, List predicates, RouteDefinitionLocator routeDefinitionLocator) { return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates, GatewayFilters, properties); } /** * 创建一个缓存路由的路由定位器 * @param routeLocators * @return */ @Bean @Primary//在相同的bean中,优先使用用@Primary注解的bean. public RouteLocator cachedCompositeRouteLocator(List routeLocators) { //1.创建组合路由定位器,根据(容器)已有的路由定位器集合 //2.创建缓存功能的路由定位器 return new CachingRouteLocator(new CompositeRouteLocator(Flux.fromIterable(routeLocators))); }
路由定位器的创建流程:
1、RouteDefinitionRouteLocator2、CompositeRouteLocator3、CachingRouteLocator其中 RouteDefinitionRouteLocator 是获取路由的主要地方,CompositeRouteLocator,CachingRouteLocator对路由定位器做了附加功能的包装,最终使用的是CachingRouteLocator对外提供服务
2.2、查看RouteLocator源码:
/** * 路由定位器,服务获取路由信息 * 可以通过 RouteDefinitionRouteLocator 获取 RouteDefinition ,并转换成 Route */public interface RouteLocator { /** * 获取路由 */ FluxgetRoutes();}
查看RouteLocator实现类
缓存功能实现→CachingRouteLocator
组合功能实现→CompositeRouteLocator
通过路由定义转换路由实现→RouteDefinitionRouteLocator
2.3、缓存功能实现→CachingRouteLocator
// 路由定位器的包装类,实现了路由的本地缓存功能public class CachingRouteLocator implements RouteLocator { //目标路由定位器 private final RouteLocator delegate; /** * 路由信息 * Flux 相当于一个 RxJava Observable, * 能够发出 0~N 个数据项,然后(可选地)completing 或 erroring。处理多个数据项作为stream */ private final Fluxroutes; // 本地缓存,用于缓存路由定位器获取的路由集合 private final Map 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 getRoutes() { return this.routes; } // 刷新缓存 public Flux 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 Monorefresh() { 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 Fluxdelegates; public CompositeRouteLocator(Flux delegates) { this.delegates = delegates; } @Override public Flux 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 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; @Autowired private Validator validator; public RouteDefinitionRouteLocator(RouteDefinitionLocator routeDefinitionLocator, List predicates, List 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 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 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 predicate = this.combinePredicates(routeDefinition); List gatewayFilters = this.getFilters(routeDefinition); return ((AsyncBuilder)Route.async(routeDefinition).asyncPredicate(predicate).replaceFilters(gatewayFilters)).build(); } private List loadGatewayFilters(String id, List filterDefinitions) { List 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 args = definition.getArgs(); if (this.logger.isDebugEnabled()) { this.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(), 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 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 getFilters(RouteDefinition routeDefinition) { List 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 combinePredicates(RouteDefinition routeDefinition) { List predicates = routeDefinition.getPredicates(); AsyncPredicate 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 lookup(RouteDefinition route, PredicateDefinition predicate) { RoutePredicateFactory
此类的核心方法getRoutes通过传入的routeDefinitionLocator获取路由定位,并循环遍历路由定位依次转换成路由返回,
代码中可以看到getRoutes通过convertToRoute方法将路由定位转换成路由的2.5.1、RouteDefinition转换:convertToRoute
// RouteDefinition 转换为对应的Route private Route convertToRoute(RouteDefinition routeDefinition) { //获取routeDefinition中的Predicate信息 Predicatepredicate = combinePredicates(routeDefinition); //获取routeDefinition中的GatewayFilter信息 List 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 PredicatecombinePredicates(RouteDefinition routeDefinition) { //获取RouteDefinition中的PredicateDefinition集合 List predicates = routeDefinition.getPredicates(); Predicate predicate = lookup(routeDefinition, predicates.get(0)); for (PredicateDefinition andPredicate : predicates.subList(1, predicates.size())) { Predicate found = lookup(routeDefinition, andPredicate); //流程4 //返回一个组合的谓词,表示该谓词与另一个谓词的短路逻辑AND predicate = predicate.and(found); } return predicate; } /** * 获取一个谓语定义(PredicateDefinition)转换的谓语 * @param route * @param predicate * @return */ @SuppressWarnings("unchecked") private Predicate lookup(RouteDefinition route, PredicateDefinition predicate) { //流程1 //流程1==获取谓语创建工厂 RoutePredicateFactory
获取Predicate流程:
- 根据PredicateDefinition name 获取 RoutePredicateFactory
- 根据PredicateDefinition args 组装 config信息
- 通过RoutePredicateFactory 根据config信息创建Predicate信息
- 多个Predicate 以短路逻辑AND组合
private ListgetFilters(RouteDefinition routeDefinition) { List 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 loadGatewayFilters(String id, List filterDefinitions) { //遍历过滤器定义,将过滤器定义转换成对应的过滤器 List 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 args = definition.getArgs(); if (logger.isDebugEnabled()) { logger.debug("RouteDefinition " + id + " applying filter " + args + " to " + definition.getName()); } //根据args组装配置信息 Map 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 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信息