当前位置:   article > 正文

Spring-Cloud-Gateway之Route初始化加载_unable to find routepredicatefactory with name -pa

unable to find routepredicatefactory with name -path

Spring-Cloud-Gateway路由信息是通过路由定位器RouteLocator加载以及初始化的接下来阅读源码看下Spring-Cloud-Gateway是怎么一步一步的实现了路由的加载初始化。


首选我们还是在Spring-Cloud-Gateway初始化配置中看Spring-Cloud-Gateway初始化是创建了路由定位相关的那些类

 

  1. ------------- GatewayAutoConfiguration类
  2. /**
  3. * 创建一个根据RouteDefinition转换的路由定位器
  4. */
  5. @Bean
  6. public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties,
  7. List<GatewayFilterFactory> GatewayFilters,
  8. List<RoutePredicateFactory> predicates,
  9. RouteDefinitionLocator routeDefinitionLocator) {
  10. return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates, GatewayFilters, properties);
  11. }
  12. /**
  13. * 创建一个缓存路由的路由定位器
  14. * @param routeLocators
  15. * @return
  16. */
  17. @Bean
  18. @Primary//意思是在众多相同的bean中,优先使用用@Primary注解的bean.
  19. //TODO: property to disable composite?
  20. public RouteLocator cachedCompositeRouteLocator(List<RouteLocator> routeLocators) {
  21. //1.创建组合路由定位器,根据(容器)已有的路由定位器集合
  22. //2.创建缓存功能的路由定位器
  23. return new CachingRouteLocator(new CompositeRouteLocator(Flux.fromIterable(routeLocators)));
  24. }

从初始化配置类中可以路由定位器的创建流程

  1. RouteDefinitionRouteLocator
  2. CompositeRouteLocator
  3. CachingRouteLocator
  • 其中 RouteDefinitionRouteLocator 是获取路由的主要地方,CompositeRouteLocator,CachingRouteLocator对路由定位器做了附加功能的包装,最终使用的是CachingRouteLocator对外提供服务

下来阅读RouteLocator 接口源码:

 

  1. /**
  2. * 路由定位器,服务获取路由信息
  3. * 1.可以通过 RouteDefinitionRouteLocator 获取 RouteDefinition ,并转换成 Route
  4. * @author Spencer Gibb
  5. */
  6. //TODO: rename to Routes?
  7. public interface RouteLocator {
  8. /**
  9. * 获取路由
  10. * @return
  11. */
  12. Flux<Route> getRoutes();
  13. }

接口很简单,有且只有一个获取路由的方法,专门用来获取路由。
RouteLocator 类图如下:

 

  1. graph TD
  2. RouteLocator-->|缓存功能实现|CachingRouteLocator
  3. RouteLocator-->|组合功能实现|CompositeRouteLocator
  4. RouteLocator-->|通过路由定义转换路由实现|RouteDefinitionRouteLocator

接下来我们依次阅读具体实现类

  • CachingRouteLocator

 

  1. /**
  2. * 路由定位器的包装类,实现了路由的本地缓存功能
  3. * @author Spencer Gibb
  4. */
  5. public class CachingRouteLocator implements RouteLocator {
  6. /**
  7. * 目标路由定位器
  8. */
  9. private final RouteLocator delegate;
  10. /**
  11. * 路由信息
  12. * Flux 相当于一个 RxJava Observable,
  13. * 能够发出 0~N 个数据项,然后(可选地)completing 或 erroring。处理多个数据项作为stream
  14. */
  15. private final Flux<Route> routes;
  16. /**
  17. * 本地缓存,用于缓存路由定位器获取的路由集合
  18. *
  19. */
  20. private final Map<String, List> cache = new HashMap<>();
  21. public CachingRouteLocator(RouteLocator delegate) {
  22. this.delegate = delegate;
  23. routes = CacheFlux.lookup(cache, "routes", Route.class)
  24. .onCacheMissResume(() -> this.delegate.getRoutes().sort(AnnotationAwareOrderComparator.INSTANCE));
  25. }
  26. @Override
  27. public Flux<Route> getRoutes() {
  28. return this.routes;
  29. }
  30. /**
  31. * Clears the routes cache
  32. * @return routes flux
  33. */
  34. public Flux<Route> refresh() {
  35. this.cache.clear();
  36. return this.routes;
  37. }
  38. @EventListener(RefreshRoutesEvent.class)
  39. /* for testing */ void handleRefresh() {
  40. refresh();
  41. }
  42. }
  1. 此类实现了对路由信息的本地缓存,通过Map<String, List> cache 缓存路由到内存中
  2. 此类通过@EventListener(RefreshRoutesEvent.class)监听RefreshRoutesEvent事件实现了对缓存的动态刷新。

备注:动态刷新可以在GatewayControllerEndpoint中通过http请求发布刷新事件

 

  1. @RestControllerEndpoint(id = "gateway")
  2. public class GatewayControllerEndpoint implements ApplicationEventPublisherAware{
  3. // 调用url= /gateway/refresh 刷新缓存中的路由信息
  4. @PostMapping("/refresh")
  5. public Mono<Void> refresh() {
  6. this.publisher.publishEvent(new RefreshRoutesEvent(this));
  7. return Mono.empty();
  8. }
  9. }
  • CompositeRouteLocator

 

  1. /**
  2. *
  3. * 组合多个 RRouteLocator 的实现,为Route提供统一获取入口
  4. * @author Spencer Gibb
  5. */
  6. public class CompositeRouteLocator implements RouteLocator {
  7. /**
  8. * 能够发出 0~N 个数据项(RouteLocator),然后(可选地)completing 或 erroring。处理多个数据项作为stream
  9. */
  10. private final Flux<RouteLocator> delegates;
  11. public CompositeRouteLocator(Flux<RouteLocator> delegates) {
  12. this.delegates = delegates;
  13. }
  14. @Override
  15. public Flux<Route> getRoutes() {
  16. //this.delegates.flatMap((routeLocator)-> routeLocator.getRoutes());
  17. return this.delegates.flatMap(RouteLocator::getRoutes);
  18. }
  19. }
  • 此类将遍历传入的目录路由定位器集合,组合每个路由定位器获取到的路由信息
  • RouteDefinitionRouteLocator

 

  1. /**
  2. * 路由定位器
  3. * 此实现通过路由定义(RouteDefinition)转换路由(Route)
  4. * {@link RouteLocator} that loads routes from a {@link RouteDefinitionLocator}
  5. * @author Spencer Gibb
  6. */
  7. public class RouteDefinitionRouteLocator implements RouteLocator, BeanFactoryAware, ApplicationEventPublisherAware {
  8. public RouteDefinitionRouteLocator(RouteDefinitionLocator routeDefinitionLocator,
  9. List<RoutePredicateFactory> predicates,
  10. List<GatewayFilterFactory> gatewayFilterFactories,
  11. GatewayProperties gatewayProperties) {
  12. this.routeDefinitionLocator = routeDefinitionLocator;
  13. initFactories(predicates);
  14. gatewayFilterFactories.forEach(factory -> this.gatewayFilterFactories.put(factory.name(), factory));
  15. this.gatewayProperties = gatewayProperties;
  16. }
  17. @Override
  18. public Flux<Route> getRoutes() {
  19. //获取到所有的RouteDefinition
  20. return this.routeDefinitionLocator.getRouteDefinitions()
  21. //遍历转换成对应的Route信息
  22. .map(this::convertToRoute)
  23. //TODO: error handling
  24. .map(route -> {
  25. if (logger.isDebugEnabled()) {
  26. logger.debug("RouteDefinition matched: " + route.getId());
  27. }
  28. return route;
  29. });
  30. /* TODO: trace logging
  31. if (logger.isTraceEnabled()) {
  32. logger.trace("RouteDefinition did not match: " + routeDefinition.getId());
  33. }*/
  34. }
  35. }
  • 此类的核心方法getRoutes通过传入的routeDefinitionLocator获取路由定位,并循环遍历路由定位依次转换成路由返回,
  • 代码中可以看到getRoutes通过convertToRoute方法将路由定位转换成路由的
  • RouteDefinitionRouteLocator:RouteDefinition转换

 

  1. /**
  2. * RouteDefinition 转换为对应的Route
  3. * @param routeDefinition
  4. * @return
  5. */
  6. private Route convertToRoute(RouteDefinition routeDefinition) {
  7. //获取routeDefinition中的Predicate信息
  8. Predicate<ServerWebExchange> predicate = combinePredicates(routeDefinition);
  9. //获取routeDefinition中的GatewayFilter信息
  10. List<GatewayFilter> gatewayFilters = getFilters(routeDefinition);
  11. //构建路由信息
  12. return Route.builder(routeDefinition)
  13. .predicate(predicate)
  14. .replaceFilters(gatewayFilters)
  15. .build();
  16. }
  • convertToRoute方法功能作用
    1. 获取routeDefinition中的Predicate信息 (通过combinePredicates方法)
    1. 获取routeDefinition中的GatewayFilter信息(通过gatewayFilters方法)
    1. 构建路由信息
  • RouteDefinitionRouteLocator:获取routeDefinition中的Predicate信息

 

  1. /**
  2. * 返回组合的谓词
  3. * @param routeDefinition
  4. * @return
  5. */
  6. private Predicate<ServerWebExchange> combinePredicates(RouteDefinition routeDefinition) {
  7. //获取RouteDefinition中的PredicateDefinition集合
  8. List<PredicateDefinition> predicates = routeDefinition.getPredicates();
  9. Predicate<ServerWebExchange> predicate = lookup(routeDefinition, predicates.get(0));
  10. for (PredicateDefinition andPredicate : predicates.subList(1, predicates.size())) {
  11. Predicate<ServerWebExchange> found = lookup(routeDefinition, andPredicate);
  12. //流程4
  13. //返回一个组合的谓词,表示该谓词与另一个谓词的短路逻辑AND
  14. predicate = predicate.and(found);
  15. }
  16. return predicate;
  17. }
  18. /**
  19. * 获取一个谓语定义(PredicateDefinition)转换的谓语
  20. * @param route
  21. * @param predicate
  22. * @return
  23. */
  24. @SuppressWarnings("unchecked")
  25. private Predicate<ServerWebExchange> lookup(RouteDefinition route, PredicateDefinition predicate) {
  26. //流程1
  27. //流程1==获取谓语创建工厂
  28. RoutePredicateFactory<Object> factory = this.predicates.get(predicate.getName());
  29. if (factory == null) {
  30. throw new IllegalArgumentException("Unable to find RoutePredicateFactory with name " + predicate.getName());
  31. }
  32. //流程2
  33. //获取参数
  34. Map<String, String> args = predicate.getArgs();
  35. if (logger.isDebugEnabled()) {
  36. logger.debug("RouteDefinition " + route.getId() + " applying "
  37. + args + " to " + predicate.getName());
  38. }
  39. //组装参数
  40. Map<String, Object> properties = factory.shortcutType().normalize(args, factory, this.parser, this.beanFactory);
  41. //构建创建谓语的配置信息
  42. Object config = factory.newConfig();
  43. ConfigurationUtils.bind(config, properties,
  44. factory.shortcutFieldPrefix(), predicate.getName(), validator);
  45. if (this.publisher != null) {
  46. this.publisher.publishEvent(new PredicateArgsEvent(this, route.getId(), properties));
  47. }
  48. //流程3
  49. //通过谓语工厂构建谓语
  50. return factory.apply(config);
  51. }

PredicateDefinition 谓语定义以及在前面文中阅读过源码了
获取Predicate流程如下

  1. 根据PredicateDefinition name 获取 RoutePredicateFactory
  2. 根据PredicateDefinition args 组装 config信息
  3. 通过RoutePredicateFactory 根据config信息创建Predicate信息
  4. 多个Predicate 以短路逻辑AND组合
  • RouteDefinitionRouteLocator:获取routeDefinition中的GatewayFilter信息

 

  1. private List<GatewayFilter> getFilters(RouteDefinition routeDefinition) {
  2. List<GatewayFilter> filters = new ArrayList<>();
  3. //校验gatewayProperties是否含义默认的过滤器集合
  4. //TODO: support option to apply defaults after route specific filters?
  5. if (!this.gatewayProperties.getDefaultFilters().isEmpty()) {
  6. //加载全局配置的默认过滤器集合
  7. filters.addAll(loadGatewayFilters("defaultFilters",
  8. this.gatewayProperties.getDefaultFilters()));
  9. }
  10. if (!routeDefinition.getFilters().isEmpty()) {
  11. //加载路由定义中的过滤器集合
  12. filters.addAll(loadGatewayFilters(routeDefinition.getId(), routeDefinition.getFilters()));
  13. }
  14. //排序
  15. AnnotationAwareOrderComparator.sort(filters);
  16. return filters;
  17. }
  18. /**
  19. * 加载过滤器,根据过滤器的定义加载
  20. * @param id
  21. * @param filterDefinitions
  22. * @return
  23. */
  24. @SuppressWarnings("unchecked")
  25. private List<GatewayFilter> loadGatewayFilters(String id, List<FilterDefinition> filterDefinitions) {
  26. //遍历过滤器定义,将过滤器定义转换成对应的过滤器
  27. List<GatewayFilter> filters = filterDefinitions.stream()
  28. .map(definition -> {
  29. //流程1 //通过过滤器定义名称获取过滤器创建工厂
  30. GatewayFilterFactory factory = this.gatewayFilterFactories.get(definition.getName());
  31. if (factory == null) {
  32. throw new IllegalArgumentException("Unable to find GatewayFilterFactory with name " + definition.getName());
  33. }
  34. //流程2
  35. //获取参数
  36. Map<String, String> args = definition.getArgs();
  37. if (logger.isDebugEnabled()) {
  38. logger.debug("RouteDefinition " + id + " applying filter " + args + " to " + definition.getName());
  39. }
  40. //根据args组装配置信息
  41. Map<String, Object> properties = factory.shortcutType().normalize(args, factory, this.parser, this.beanFactory);
  42. //构建过滤器创建配置信息
  43. Object configuration = factory.newConfig();
  44. ConfigurationUtils.bind(configuration, properties,
  45. factory.shortcutFieldPrefix(), definition.getName(), validator);
  46. //流程3
  47. //通过过滤器工厂创建GatewayFilter
  48. GatewayFilter gatewayFilter = factory.apply(configuration);
  49. if (this.publisher != null) {
  50. //发布事件
  51. this.publisher.publishEvent(new FilterArgsEvent(this, id, properties));
  52. }
  53. return gatewayFilter;
  54. })
  55. .collect(Collectors.toList());
  56. ArrayList<GatewayFilter> ordered = new ArrayList<>(filters.size());
  57. //包装过滤器使其所有过滤器继承Ordered属性,可进行排序
  58. for (int i = 0; i < filters.size(); i++) {
  59. GatewayFilter gatewayFilter = filters.get(i);
  60. if (gatewayFilter instanceof Ordered) {
  61. ordered.add(gatewayFilter);
  62. }
  63. else {
  64. ordered.add(new OrderedGatewayFilter(gatewayFilter, i + 1));
  65. }
  66. }
  67. return ordered;
  68. }
  • getFilters 方法 同时加载 全局配置 gatewayProperties与routeDefinition配置下的所有过滤器定义filterDefinitions
  • loadGatewayFilters 负责将filterDefinition转化成对应的GatewayFilter
    转化流程如下
  1. 根据filterDefinition name 获取 GatewayFilterFactory
  2. 根据filterDefinition args 组装 config信息
  3. 通过GatewayFilterFactory 根据config信息创建PGatewayFilter信息

至此,阅读了路由的数据模型,路由定义加载,路由的加载(路由定义转化为路由),Spring-Cloud-Gateway路由的创建加载流程已经清晰明了的展现出来,在使用中也可以快速的对其扩展,以及根据实际需求进行个性化的定制操作。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/301308
推荐阅读
相关标签
  

闽ICP备14008679号