Spring Cloud Gateway(五):路由定位器 RouteLocator
本文基于 spring cloud gateway 2.0.1
1、简介
直接 获取 路 由 的 方法 是 通过 RouteLocator 接口 获取。 同样, 该 顶 级 接口 有多 个 实现 类,
RouteLocator 路由定位器,顾名思义就是用来获取路由的方法。该路由定位器为顶级接口有多个实现类,如类图所示,本节会对其实现类一一进行介绍。
通过类图可知,路由定位器接口有三种实现方法:
- RouteDefinitionRouteLocator 基于路由定义的定位器
- CachingRouteLocator 基于缓存的路由定位器
- CompositeRouteLocator 基于组合方式的路由定位器
2、RouteLocator 路由定位器
与上节学习的路由定义定位器接口类似,RouteLocator 路由定位器只有一个 getRoutes 方法,用来获取路由信息。
public interface RouteLocator {//获取路由对象Flux<Route> getRoutes();
}
2.1、Route 路由对象
Route 路由定义了路由断言、过滤器、路由地址及路由优先级等信息。当请求到达时,在转发到代理服务之前,会依次经过路由断言匹配路由 和 网关过滤器处理。
public class Route implements Ordered {//路由 Id private final String id; //路由地址 private final URI uri; //路由的优先级 private final int order; //路由断言,判断请求路径是否匹配private final AsyncPredicate<ServerWebExchange> predicate;//网关过滤器private final List<GatewayFilter> gatewayFilters;-----------------------省略-------------------------
}
3、 RouteDefinitionRouteLocator 基于路由定义的定位器
3.1、初始化
RouteDefinitionRouteLocator 构造函数有多个参数:路由定义定位器、路由断言工厂、网关过滤器及网关配置对象。 根据传入的参数,设置 routeDefinitionLocator 和 网关配置,并初始化路由断言 和 网关过滤器。 RouteDefinitionRouteLocator 的实现方式是基于路由定义来获取路由,它实现了 RouteLocator 接口,用来获取路由信息。
public class RouteDefinitionRouteLocator implements RouteLocator, BeanFactoryAware, ApplicationEventPublisherAware {protected final Log logger = LogFactory.getLog(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;public RouteDefinitionRouteLocator(RouteDefinitionLocator routeDefinitionLocator,List<RoutePredicateFactory> predicates,List<GatewayFilterFactory> gatewayFilterFactories,GatewayProperties gatewayProperties) {//设置路由定义定位器this.routeDefinitionLocator = routeDefinitionLocator;//初始化路由断言工厂initFactories(predicates);//初始化网关过滤器gatewayFilterFactories.forEach(factory -> this.gatewayFilterFactories.put(factory.name(), factory));this.gatewayProperties = gatewayProperties;}@Autowiredprivate Validator validator;@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {this.beanFactory = beanFactory;}@Overridepublic 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 (logger.isInfoEnabled()) {logger.info("Loaded RoutePredicateFactory [" + key + "]");}});}--------------------------------省略---------------------------------
}
- 此种方式的路由获取是通过 RouteDefinitionRouteLocator 获取 RouteDefinition 并将路由定义转换成路由对象
- 这里的routeDefinitionLocator是CompositeRouteDefinitionLocator,它组合了InMemoryRouteDefinitionRepository、PropertiesRouteDefinitionLocator、DiscoveryClientRouteDefinitionLocator三个RouteDefinitionLocator。
- PropertiesRouteDefinitionLocator是直接使用GatewayProperties的getRoutes()获取,其是通过spring.cloud.gateway.routes配置得来。
3.2、RouteDefinition 转换成 Route 的流程
![image](
// RouteDefinitionRouteLocator.java
@Overridepublic Flux<Route> getRoutes() {return this.routeDefinitionLocator.getRouteDefinitions().map(this::convertToRoute)//TODO: error handling.map(route -> {if (logger.isDebugEnabled()) {logger.debug("RouteDefinition matched: " + route.getId());}return route;});/* TODO: trace loggingif (logger.isTraceEnabled()) {logger.trace("RouteDefinition did not match: " + routeDefinition.getId());}*/}private Route convertToRoute(RouteDefinition routeDefinition) {AsyncPredicate<ServerWebExchange> predicate = combinePredicates(routeDefinition);List<GatewayFilter> gatewayFilters = getFilters(routeDefinition);return Route.async(routeDefinition).asyncPredicate(predicate).replaceFilters(gatewayFilters).build();}
getRoutes() :根据传入的 RouteDefinitionLocator 获取路由定义对象,使用map方法将每个 RouteDefinition 转换为 Route。
RouteDefinitionLocator#convertToRoute :是具体的转换方法,转换过程中涉及到路由断言 和 网关过滤器的处理,最后构建为Route 对象。
此处网关过滤器处理包括两种,一种是默认过滤器,作用于所有路由;一种是指定路由的自定义过滤器。首先获取默认过滤器,根据过滤器名称获取对应的过滤器,最终转换成有优先级的OrderedGatewayFilter。
3.2.1、convertToRoute##combinePredicates
combinePredicates主要是对找出来的predicate进行and操作
private AsyncPredicate<ServerWebExchange> combinePredicates(RouteDefinition routeDefinition) {List<PredicateDefinition> predicates = routeDefinition.getPredicates();AsyncPredicate<ServerWebExchange> predicate = lookup(routeDefinition, predicates.get(0));for (PredicateDefinition andPredicate : predicates.subList(1, predicates.size())) {AsyncPredicate<ServerWebExchange> found = lookup(routeDefinition, andPredicate);predicate = predicate.and(found);}return predicate;}@SuppressWarnings("unchecked")private AsyncPredicate<ServerWebExchange> lookup(RouteDefinition route, PredicateDefinition predicate) {RoutePredicateFactory<Object> factory = this.predicates.get(predicate.getName());if (factory == null) {throw new IllegalArgumentException("Unable to find RoutePredicateFactory with name " + predicate.getName());}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));}return factory.applyAsync(config);}
3.2.2、convertToRoute##getFilters
getFilters 主要是利用loadGatewayFilters获取filter,使用AnnotationAwareOrderComparator进行排序
loadGatewayFilters利用工厂方法,使用GatewayFilterFactory根据config 获取具体的GatewayFilter实例
@SuppressWarnings("unchecked")private List<GatewayFilter> loadGatewayFilters(String id, List<FilterDefinition> filterDefinitions) {List<GatewayFilter> filters = filterDefinitions.stream().map(definition -> {GatewayFilterFactory factory = this.gatewayFilterFactories.get(definition.getName());if (factory == null) {throw new IllegalArgumentException("Unable to find GatewayFilterFactory with name " + definition.getName());}Map<String, String> args = definition.getArgs();if (logger.isDebugEnabled()) {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(), 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 = 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<>();//TODO: support option to apply defaults after route specific filters?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;}
4、 CachingRouteLocator 基于缓存的路由定位器
public class CachingRouteLocator implements RouteLocator {private final RouteLocator delegate;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));}@Overridepublic Flux<Route> getRoutes() {return this.routes;}/*** Clears the routes cache* @return routes flux*/public Flux<Route> refresh() {this.cache.clear();return this.routes;}@EventListener(RefreshRoutesEvent.class)/* for testing */ void handleRefresh() {refresh();}
}
基于缓存的路由定位器比较简单和缓存路由定义定位器比较类似,只需要调用 RouteLocator# getRoutes 即可获取路由。
根据传入的路由定位器获取路由信息并存储到缓存中。通过监听 RefreshRoutesEvent 事件刷新缓存的路由信息。
5、 CompositeRouteLocator 基于组合方式的路由定位器
public class CompositeRouteLocator implements RouteLocator {private final Flux<RouteLocator> delegates;public CompositeRouteLocator(Flux<RouteLocator> delegates) {this.delegates = delegates;}@Overridepublic Flux<Route> getRoutes() {return this.delegates.flatMap(RouteLocator::getRoutes);}
}
组合方式的路由定位器,将实现 RouteLocator 接口的路由定位器组合在一起,提供获取路由的统一入口。
6、小结
RouteLocator 接口用于获取路由信息,其有三个实现类
- RouteDefinitionRouteLocator
- CompositeRouteLocator
- CachingRouteLocator
最终使用的是CachingRouteLocator,它包装了CompositeRouteLocator,而CompositeRouteLocator则组合了RouteDefinitionRouteLocator。
RouteDefinitionRouteLocator 与 RouteDefinitionLocator比较容易混淆,前者是一个RouteLocator(路由定位器),后者是一个RouteDefinitionLocator(路由定义定位器),前者的 RouteDefinitionRouteLocator 主要从后者获取路由定义信息。
转载于:https://www.cnblogs.com/liukaifeng/p/10055868.html
Spring Cloud Gateway(五):路由定位器 RouteLocator相关推荐
- Spring Cloud Gateway 动态路由管理,一点都不吹,应该没有比这更好的管理系统了吧
本文介绍的 Spring Cloud Gateway 动态路由.不比其他博客通篇 copy 的 Gateway 动态路由,直接上干货!!!为你们提供了一套完整的动态路由管理系统.文末附本文全套代码 ...
- Spring Cloud Gateway(路由)
本篇文章主要介绍了什么是 Spring Cloud Gateway,并基于 Spring Cloud Gateway 的 Finchley.RC1 版本编写一个 Spring Cloud Gatewa ...
- Nacos + Spring Cloud Gateway动态路由配置
前言 Nacos最近项目一直在使用,其简单灵活,支持更细粒度的命令空间,分组等为麻烦复杂的环境切换提供了方便:同时也很好支持动态路由的配置,只需要简单的几步即可.在国产的注册中心.配置中心中比较突出, ...
- Spring Cloud Gateway之路由断言工厂篇
1. 背景 最近,需要提升系统安全性,市面上有很多款网关服务的技术方案,最终选择了Spring Cloud Gateway. 2. Spring Cloud Gateway工作机制 官网配图: 客户端 ...
- Spring Cloud Gateway动态路由实现
Gateway上线部署分析 当你的网关程序开发完成之后,需要部署到生产环境,这个时候你的程序不能是单点运行的,肯定是多节点启动(独立部署或者docker等容器部署),防止单节点故障导致整个服务不能访问 ...
- 三分钟了解Spring Cloud Gateway路由转发之自动路由
文章目录 一.前言 二.路由配置 1. 静态路由 2. 动态路由 3. 自动路由 三.Spring Cloud Gateway 是如何实现动态路由 工作原理 源码解析 路由转发原理 路由转发源码解析 ...
- 第五章 微服务网关Spring Cloud Gateway
5.1 微服务网关简介 第三章我们介绍了通过Spring Cloud LoadBalancer实现了微服务之间的调⽤和负载均衡,以及使⽤Spring Cloud OpenFeign声明式调⽤,那我们的 ...
- Spring Cloud Gateway 路由转发之After(Before)路由断言工厂使用
前言 本文旨在介绍After(Before)路由断言工厂使用,以此类推可以使用其他路由断言工厂 案例 1.概念 网关简单的说就是提供一个对外统一的API入口和出口,统管企业对外的所有API出口.一般来 ...
- spring cloud gateway 之动态路由
前面分别对 Spring Cloud Zuul 与 Spring Cloud Gateway 进行了简单的说明,它门是API网关,API网关负责服务请求路由.组合及协议转换,客户端的所有请求都首先经过 ...
- Spring Cloud Gateway 3.1.3最新版中文手册官网2022
Spring Cloud Gateway 3.1.3 该项目提供了一个库,用于在 Spring WebFlux 之上构建 API 网关.Spring Cloud Gateway 旨在提供一种简单而有效 ...
最新文章
- linux系统内存执行elf的多种方式
- window7调用计算机,Windows7自带计算器的使用
- HDU4473_Exam
- 绿证交易全凭自愿 哪些企业会为其买单?
- Linux下Makefile学习笔记
- 依赖反转原理,IoC容器和依赖注入:第2部分
- android ble 大小,Android BLE中传输数据的最大长度怎么破
- IIS启用GZip压缩
- SpringApplication run方法解析:SpringApplicationRunListeners(二)
- Oracle字符集设置
- 在计算机上采用线性同余法,随机数生成算法 —— 线性同余法
- 天猫精灵测评与开发案例
- 域服务器桌面墙纸,与大家分享windows 10 加域后统一桌面壁纸无法生效问题的解决办法...
- diy服务器个人主机_电脑小白如何自己动手DIY主机?
- Python IDLE的下载,安装和使用
- 港大HKU邮箱(connect.hku.hk)添加至iphone 自带邮箱方法
- s8 android 8.0变化,三星s8何时能更新android8.0
- 【小说】玻璃碎片-第二章
- c语言程序(十八)——迭代计算
- 什么是剩余参数 ...arg
热门文章
- Master of GCD(差分数组||线段树)
- bzoj3252攻略(线段树+dfs序)或者(树链剖分+dfs)
- Kettle安装好MYSQL驱动后报用户名密码错误
- mysql workbench 6.2.3 linux_MySQL Workbench 6.2.1 BETA 发布
- html预览图片的功能,javascript实现的图片预览功能
- plsql如何显示表结构图_工地新人如何看懂图纸
- [深度学习] 分布式模式介绍(一)
- 开漏(open drain)和开集(open collector)
- 卡尔曼滤波(Calman Filter)基本原理
- 【目标检测_概述】recent advances in deep learning for object detection_2019