在Spring-Cloud-Gateway初始化時,同時GatewayAutoConfiguration核心配置類會被初始化加載以下 :html
NettyConfiguration 底層通訊netty配置
GlobalFilter (AdaptCachedBodyGlobalFilter,RouteToRequestUrlFilter,ForwardRoutingFilter,ForwardPathFilter,WebsocketRoutingFilter,WeightCalculatorWebFilter等)
FilteringWebHandler
GatewayProperties
PrefixPathGatewayFilterFactory
RoutePredicateFactory
RouteDefinitionLocator
RouteLocator
RoutePredicateHandlerMapping 查找匹配到 Route並進行處理
GatewayWebfluxEndpoint 管理網關的 HTTP API
其中在GatewayAutoConfiguration配置加載中含初始化加載GatewayProperties實例的配置:java
查看GatewayAutoConfiguration源碼:react
@Bean public GatewayProperties gatewayProperties() { return new GatewayProperties(); }
1.二、再次查看GatewayProperties源碼:web
@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
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的配置也是如此。express
字符傳格式:name=param1,param2,param3apache
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]); } } }
/** * 建立一個根據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對外提供服務
/** * 路由定位器,服務獲取路由信息 * 能夠經過 RouteDefinitionRouteLocator 獲取 RouteDefinition ,並轉換成 Route */ public interface RouteLocator { /** * 獲取路由 */ Flux<Route> getRoutes(); }
查看RouteLocator實現類websocket
// 路由定位器的包裝類,實現了路由的本地緩存功能 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(); } }
一、路由信息的本地緩存,經過Map<String, List> cache 緩存路由到內存中;
二、此類經過@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(); } }
//組合多個 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); } }
此類將遍歷傳入的目錄路由定位器集合,組合每一個路由定位器獲取到的路由信息
// // 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方法將路由定位轉換成路由的
// 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方法)
構建路由信息
一、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流程:
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; }