Spring Cloud Gateway源码系列之路由配置加载过程
当前章节主要是讲解配置文件中定义的路由配置被gateway加载,同时转为可以直接操作的路由对象
引入pom坐标
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
前提:需要对springboot的自动装配要非常的熟悉,还有对reactor编程有一些了解,在分析过程中会对reactor一些基础进行讲一下
1. 找到组件加载入口spring.factories
在包spring-cloud-gateway-server包下,找到spring.factories文件(springboot的自动装配)
2. GatewayAutoConfiguration 自动装配类
最主要的装配类为GatewayAutoConfiguration
3. 加载配置文件中路由信息
@Bean
public GatewayProperties gatewayProperties() {return new GatewayProperties();
}
4. GatewayProperties对象
我们在配置文件中配置的路由规则会在启动的时候都加载到该对象中
@ConfigurationProperties(GatewayProperties.PREFIX)
@Validated
public class GatewayProperties {public static final String PREFIX = "spring.cloud.gateway";//路由配置private List<RouteDefinition> routes = new ArrayList<>(); //默认的过滤器private List<FilterDefinition> defaultFilters = new ArrayList<>(); private List<MediaType> streamingMediaTypes = Arrays.asList(MediaType.TEXT_EVENT_STREAM, MediaType.APPLICATION_STREAM_JSON);private boolean failOnRouteDefinitionError = true;// 统计配置private Metrics metrics = new Metrics();
}
5. RouteDefinition每个路由的详细配置
路由的格式
spring:cloud:gateway:routes:- id: testuri: http://localhost:8081predicates:- Path=/test/**- id: test2uri: http://localhost:8082predicates:- Path=/api/**
对应的路由配置
public class RouteDefinition {// 路由唯一标识private String id;// 路由规则private List<PredicateDefinition> predicates = new ArrayList<>();// 指定路由的过滤器private List<FilterDefinition> filters = new ArrayList<>();// 路由匹配后请求的地址private URI uri;// 元数据private Map<String, Object> metadata = new HashMap<>();// 加载序列private int order = 0;
}
6. 将路由的定义信息转为路由控制对象
在装配类GatewayAutoConfiguration中找到一下装配对象
@Bean
public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties, // 路由定义信息List<GatewayFilterFactory> gatewayFilters, // 过滤器,之后的章节中进行分析List<RoutePredicateFactory> predicates, //路由器匹配规则RouteDefinitionLocator routeDefinitionLocator, //路由定义信息加载器ConfigurationService configurationService) {return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates,gatewayFilters, properties, configurationService);
}
7. RouteDefinitionRouteLocator对象实例化构建
public RouteDefinitionRouteLocator(RouteDefinitionLocator routeDefinitionLocator,List<RoutePredicateFactory> predicates,List<GatewayFilterFactory> gatewayFilterFactories,GatewayProperties gatewayProperties,ConfigurationService configurationService) {this.routeDefinitionLocator = routeDefinitionLocator;this.configurationService = configurationService;initFactories(predicates); // 初始化路由匹配工厂gatewayFilterFactories.forEach( //加载生成过滤器的工厂factory -> this.gatewayFilterFactories.put(factory.name(), factory));this.gatewayProperties = gatewayProperties;
}
a. initFactories(predicates) 初始化路由匹配工厂
主要是将路由匹配规则转换为断言对象,用来对每个请求的url进行判断是否使用该规则下的路由地址
private void initFactories(List<RoutePredicateFactory> predicates) {predicates.forEach(factory -> {String key = factory.name();if (this.predicates.containsKey(key)) {//打印日志}this.predicates.put(key, factory);});
}
this.predicates的存储最后结果如下图,加载多种路由工厂
在我们的配置匹配规则时,会有类似于Path=/test/**前面的Path或者其它的,它是来决定使用哪个工厂来生成断言对象的。不同的规则有不同的方式。具体的路由匹配规则在下一章进行分析。
b. gatewayFilterFactories.forEach( factory -> this.gatewayFilterFactories.put(factory.name(), factory));
加载所有可以选择的过滤器
spring:cloud:gateway:routes:- id: testuri: http://localhost:8081predicates:- Path=/test/**- Query=param, valuefilters: 过滤器- AddRequestHeader=key,value
加载过滤器,gatewayFilterFactories是自动装配的bean,也都在GatewayAutoConfiguration中进行装配,gateway提供了很多可以在路由配置加的过滤器,例如:AddRequestHeader=key,value。
8. RouteDefinitionRouteLocator对象中getRoutes() 获取路由器
a. 这个方法主要上将配置文件中的路由定义信息转为可操作的路由对象
@Override
public Flux<Route> getRoutes() {// 通过定义信息转为路由对象集Route// routeDefinitionLocator.getRouteDefinitions路由的定义信息// 重点在convertToRoute方法中Flux<Route> routes = this.routeDefinitionLocator.getRouteDefinitions().map(this::convertToRoute);// 路由配置错误是否只是打印日志if (!gatewayProperties.isFailOnRouteDefinitionError()) {// instead of letting error bubble up, continueroutes = routes.onErrorContinue((error, obj) -> {if (logger.isWarnEnabled()) {logger.warn("RouteDefinition id " + ((RouteDefinition) obj).getId()+ " will be ignored. Definition has invalid configs, "+ error.getMessage());}});}// 打印配置的所有路由ID日志return routes.map(route -> {if (logger.isDebugEnabled()) {logger.debug("RouteDefinition matched: " + route.getId());}return route;});
}
Flux可以理解为java8中提供的Stream类,包含的是0-n个对象,可以对包含的对象做批量处理,像在Stream中一样做过滤、排序、映射…
b. Route对象
public class Route implements Ordered {// 路由IDprivate final String id;// 路由目标地址private final URI uri;// 路由加载顺序private final int order;// 该路由下的断言,也就是将匹配规则转为断言对象,是否执行该路由private final AsyncPredicate<ServerWebExchange> predicate;// 过滤器private final List<GatewayFilter> gatewayFilters;// 元数据private final Map<String, Object> metadata;
}
predicate对象实际上就是一组规约对象,对一次请求进行判断是否使用该路由,这个对象实际上是包含一组,我们在配置路由规则时可以配置多个,所以需要所有的都匹配成功了才使用当前路由
c. convertToRoute方法
将路由定义信息转为路由对象
private Route convertToRoute(RouteDefinition routeDefinition) {//获取路由下的匹配规则断言,具体实现可以看<路由匹配规则> 之后章节讲解AsyncPredicate<ServerWebExchange> predicate = combinePredicates(routeDefinition);//获取过滤器,包括gateway下的统一配置过滤器和路由下单独配的过滤器,之后章节详细讲解List<GatewayFilter> gatewayFilters = getFilters(routeDefinition);return Route.async(routeDefinition).asyncPredicate(predicate).replaceFilters(gatewayFilters).build();
}
d. 获取过滤器
配置文件
spring:cloud:gateway:default-filters: // 默认过滤器(全局过滤器)- AddRequestHeader=key,valueroutes:- id: testuri: http://localhost:8081predicates:- Path=/test/**- Query=param, valuefilters: // 路由器下特定过滤器- AddRequestHeader=key,valueorder: 1
获取过滤器细节
private List<GatewayFilter> getFilters(RouteDefinition routeDefinition) {List<GatewayFilter> filters = new ArrayList<>();// 获取全局过滤器,所有路由器共享if (!this.gatewayProperties.getDefaultFilters().isEmpty()) {filters.addAll(loadGatewayFilters(DEFAULT_FILTERS,new ArrayList<>(this.gatewayProperties.getDefaultFilters())));}// 获取路由器下特定过滤器if (!routeDefinition.getFilters().isEmpty()) {filters.addAll(loadGatewayFilters(routeDefinition.getId(),new ArrayList<>(routeDefinition.getFilters())));}//过滤器排序AnnotationAwareOrderComparator.sort(filters);return filters;
}/** 获取指定过滤器的执行逻辑列表 */
List<GatewayFilter> loadGatewayFilters(String id,List<FilterDefinition> filterDefinitions) {ArrayList<GatewayFilter> ordered = new ArrayList<>(filterDefinitions.size());for (int i = 0; i < filterDefinitions.size(); i++) {FilterDefinition definition = filterDefinitions.get(i);// 从所有的过滤器中找到需要那个过滤器GatewayFilterFactory factory = this.gatewayFilterFactories.get(definition.getName());// 校验抛异常,省略。。。// 构建过滤器所需参数Object configuration = this.configurationService.with(factory).name(definition.getName()).properties(definition.getArgs()).eventFunction((bound, properties) -> new FilterArgsEvent(// TODO: why explicit cast needed or java compile failsRouteDefinitionRouteLocator.this, id, (Map<String, Object>) properties)).bind();// 有些过滤器需要路由的IDif (configuration instanceof HasRouteId) {HasRouteId hasRouteId = (HasRouteId) configuration;hasRouteId.setRouteId(id);}// 通过指定的过滤工厂生成该路由的过滤器GatewayFilter gatewayFilter = factory.apply(configuration);// 如果得到的过滤器没有排序,则进行给排序设置if (gatewayFilter instanceof Ordered) {ordered.add(gatewayFilter);}else {ordered.add(new OrderedGatewayFilter(gatewayFilter, i + 1));}}//将过滤器集合返回return ordered;
}
10. 总结
至此,加载路由配置的功能已经完成,可以通过RouteDefinitionRouteLocator的getRoutes()方法获取到所有的路由器列表Flux,它可以对应该请求进行校验是否匹配某个路由规则,并且依次执行全局过滤器以及可选过滤器
Spring Cloud Gateway源码系列之路由配置加载过程相关推荐
- Spring Cloud Gateway 源码解析(1) —— 基础
目录 Gateway初始化 启用Gateway GatewayClassPathWarningAutoConfiguration GatewayLoadBalancerClientAutoConfig ...
- Spring cloud Gateway 源码(二) 路由流程
目录 1.DispatcherHandler 1.1 handle方法 1.1.1 getHandler 获取请求处理器 1.1.2 invokeHandler 执行 2.路由选择 2.1 选择目标 ...
- Spring Cloud Gateway 源码解析(2) —— 路由
目录 基本组件 路由定位器(RouteDefinitionLocator ) 路由定义(RouteDefinition) PredicateDefinition FilterDefinition Co ...
- api网关揭秘--spring cloud gateway源码解析
要想了解spring cloud gateway的源码,要熟悉spring webflux,我的上篇文章介绍了spring webflux. 1.gateway 和zuul对比 I am the au ...
- Spring Cloud Gateway 源码解析(3) —— Predicate
目录 RoutePredicateFactory GatewayPredicate AfterRoutePredicateFactory RoutePredicateHandlerMapping Fi ...
- Spring Cloud Gateway 源码解析(4)-- filter
文章目录 绑定Filter HandlerMapping Filter GatewayFilterChain FilteringWebHandler GlobalFilter实例化 GatewayFi ...
- 框架源码专题:springIOC的加载过程,bean的生命周期,结合spring源码分析
文章目录 1.BeanFactory和ApplicationContext的区别? 2. IOC与 Bean的加载过程 ①:初始化容器DefaultListableBeanFactory ②:创建读取 ...
- Myabtis源码分析五-Mybatis配置加载完全图解,建造者模式的使用,涵盖Java各种技术栈
private SqlSessionFactory sqlSessionFactory; @Before public void init() throws IOException { //----- ...
- Spring Cloud Hystrix 源码系列:工作原理
Hystrix 译为 "豪猪",豪猪的棘刺能保护自己不受天敌伤害,代表了强大的防御能力.Hystrix 基于 RxJava 进行实现,RxJava 是一种基于观察者模式的响应式编程 ...
最新文章
- Centos rescue 模式
- oracle用dba登陆怎么登,以SQLDBA身份登录isqlplus
- 十一、深入JavaScript的定时器(七)
- 51nod 1534 棋子游戏
- ajax实现下拉列表联动
- 用html和css布局如下图像,[看书][CSS精粹(第2版)]第三章 CSS和图像 HTML网页布局...
- HttpClient连接池的连接保持、超时和失效机制
- 基于 libevent 开源框架实现的 web 服务器
- maya oracle 黄种子,nvidia physX 2.89 for MAYAMAX(BT种子下载)
- 软考初级程序员---题目(五)
- gitlab . pre-receive hook declined
- 【A40I-LVDS】
- JS--JavaScript数组Array(join、split、reverse、concat、slice)详解
- Ant Design Pro初探
- 【论文阅读术语】benchmark、baseline、backbone、ground truth
- 射频测试 —— 蓝牙定频测试3
- Android开发之Audio播放:竞争Audio之Audio Focus的应用
- 必应输入法VS搜狗拼音
- 入门3D游戏建模,为什么建议先学3dsmax,而不是Maya
- 区块链3.0:您的资产上链了吗?