博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
006-spring cloud gateway-GatewayAutoConfiguration核心配置-GatewayProperties初始化加载、Route初始化加载...
阅读量:5966 次
发布时间:2019-06-19

本文共 20932 字,大约阅读时间需要 69 分钟。

一、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 List
routes = 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:网关网络媒体类型,列表形式
其中routes是RouteDefinition集合,defaultFilters是FilterDefinition集合,参看具体的 字段。实际配置文件可如下:
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路由信息是通过路由定位器RouteLocator加载以及初始化。
  在Spring-Cloud-Gateway初始化时,同时GatewayAutoConfiguration核心配置类会被初始化加载如下 :
/**     * 创建一个根据RouteDefinition转换的路由定位器     */    @Bean    public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties,                                                   List
GatewayFilters, 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 {    /**     * 获取路由     */    Flux
getRoutes();}

查看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 Flux
routes; // 本地缓存,用于缓存路由定位器获取的路由集合 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 Mono
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
delegates; 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 Map
predicates = 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
factory = (RoutePredicateFactory)this.predicates.get(predicate.getName()); if (factory == null) { throw new IllegalArgumentException("Unable to find RoutePredicateFactory with name " + predicate.getName()); } else { Map
args = predicate.getArgs(); if (this.logger.isDebugEnabled()) { this.logger.debug("RouteDefinition " + route.getId() + " applying " + args + " to " + predicate.getName()); } Map
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); } }}
View Code

此类的核心方法getRoutes通过传入的routeDefinitionLocator获取路由定位,并循环遍历路由定位依次转换成路由返回,

代码中可以看到getRoutes通过convertToRoute方法将路由定位转换成路由的

2.5.1、RouteDefinition转换:convertToRoute

// RouteDefinition 转换为对应的Route    private Route convertToRoute(RouteDefinition routeDefinition) {        //获取routeDefinition中的Predicate信息        Predicate
predicate = 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 Predicate
combinePredicates(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
factory = this.predicates.get(predicate.getName()); if (factory == null) { throw new IllegalArgumentException("Unable to find RoutePredicateFactory with name " + predicate.getName()); } //流程2 //获取参数 Map
args = predicate.getArgs(); if (logger.isDebugEnabled()) { logger.debug("RouteDefinition " + route.getId() + " applying " + args + " to " + predicate.getName()); } //组装参数 Map
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组合
2、convertToRoute中 getFilters获取routeDefinition中的GatewayFilter信息
private List
getFilters(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
    转化流程如下
  1. 根据filterDefinition name 获取 GatewayFilterFactory
  2. 根据filterDefinition args 组装 config信息
  3. 通过GatewayFilterFactory 根据config信息创建PGatewayFilter信息

转载地址:http://oqmax.baihongyu.com/

你可能感兴趣的文章
深入理解html5系列-文本标签
查看>>
mysql基础知识点
查看>>
Microsoft.System.Center.Operations.Manager.2007 中文版完整光盘下载地址
查看>>
Python快速教程
查看>>
我的友情链接
查看>>
ssh免密码登录
查看>>
Linux下Django环境安装
查看>>
如何在指定的内容中找出指定字符串的个数
查看>>
我的友情链接
查看>>
浅谈如何用We7站群平台打造垂直性政务网站
查看>>
我的友情链接
查看>>
Traversing Mapping Filtering Folding Reducing
查看>>
Go bytes包
查看>>
Spring MVC请求处理流程分析
查看>>
ORACLE--Connect By、Level、Start With的使用(Hierarchical query-层次查询)
查看>>
生产环境MySQL 5.5.x单机多实例配置实践
查看>>
Web应用工作原理、动态网页技术
查看>>
EXCEL工作表保护密码破解 宏撤销保护图文教程
查看>>
Catalan数(卡特兰数)
查看>>
Linux shell的条件判断、循环语句及实例
查看>>