Spring Cloud Gateway 过滤器执行顺序原理分析
过滤器类型
GlobalFilter:全局过滤器,对所有路由生效。通过实现GlobalFilter接口创建
GatewayFilter:网关过滤器,也可以说是局部过滤器、自定义过滤器,只对配置了此过滤器的路由生效。通过GatewayFilterFactory创建。
过滤器会被执行两次,过滤分为pre和post。
pre:请求前调用。
post:响应结果返回时调用,顺序和pre完全相反,这里只讨论过滤器的pre执行顺序,post倒置过来就行了。
先说结论
结论
网上的说法都不太准确,其实并没有多花里胡哨的。
最终都是通过Order值进行排序执行,Order值越小越先执行。
源码在org.springframework.cloud.gateway.handler.FilteringWebHandler#handle方法里面
AnnotationAwareOrderComparator.sort(combined);
至于为什么会出现一些莫名其妙的排序情况,都是Order值相同或者不理解Order值生成规则照成的。下面先解释这两点,最后会通过代码验证,源码分析加以说明。
Order值相同时
1.两个GlobalFilter类型的过滤器Order值相同时,根据文件名字母排序,文件名靠前的优先更高。
原因是包扫描时是按照文件的顺序扫描的,然后封装到List集合的,通过Order值排序时如果Order值相同,文件名在前名的依然会排在前面。
2.GlobalFilter类型和GatewayFilter类型的过滤器Order值相同时,GlobalFilter类型优先更高。
原因是这两种过滤器最终会合并到一个过滤器集合中形成过滤器调用链,源码是通过list.addAll();方法将GatewayFilter类型的过滤器加到了GlobalFilter过滤器集合中,addAll()是末尾添加方式,所以Order值相同时GatewayFilter类型的过滤器会排在后面。
Order值生成规则
1.GlobalFilter类型过滤器,通过实现Ordered接口的getOrder()方法设置。
2.GatewayFilter类型过滤器,无法手动设置Order值,通过配置文件中配置的过滤器顺序自动生成,固定从1开始封装,例如配置了三个过滤器,则按照从上往下顺序Order值依次为1、2、3。
补充说明:GatewayFilter也可以自定义顺序,详见:Spring Cloud Gateway GatewayFilter自定义过滤器顺序_xzh_blog-CSDN博客
代码验证
定义GlobalFilter过滤器
@Component
public class GaFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {System.out.println("Ga 1");return chain.filter(exchange);}@Overridepublic int getOrder() {return 1;}
}
@Component
public class GbFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {System.out.println("Gb 2");return chain.filter(exchange);}@Overridepublic int getOrder() {return 2;}
}
@Component
public class GcFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {System.out.println("Gc 1");return chain.filter(exchange);}@Overridepublic int getOrder() {return 1;}
}
定义GatewayFilter过滤器
注意:这里为了简单,直接继承自AbstractNameValueGatewayFilterFactory,实际使用看自己需求选择继承类
@Component
public class FaGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {@Overridepublic GatewayFilter apply(NameValueConfig config) {return (exchange, chain) -> {System.out.println("Fa");return chain.filter(exchange);};}
}
@Component
public class FbGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {@Overridepublic GatewayFilter apply(NameValueConfig config) {return (exchange, chain) -> {System.out.println("Fb");return chain.filter(exchange);};}
}
@Component
public class FcGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {@Overridepublic GatewayFilter apply(NameValueConfig config) {return (exchange, chain) -> {System.out.println("Fc");return chain.filter(exchange);};}
}
GatewayFilter类型的过滤器,只在配置了此过滤器的路由服务上生效,所以需要加到路由配置上,"="后面的n,v为NameValueConfig里面的值,这里随便写一下。
routes:- id: 用户服务uri: lb://user-servicepredicates:- Path=/user-service/**filters:- Fa=n, v- Fc=n, v- Fb=n, v
结果输出
Ga 1
Gc 1
Fa
Gb 2
Fc
Fb
源码分析
服务启动时,org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator会将路由中配置了的过滤器加载到路由的过滤器集合中,并封装Order值。
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());// 遍历过滤器集合,封装成带Order值的过滤器集合for(int i = 0; i < filters.size(); ++i) {GatewayFilter gatewayFilter = (GatewayFilter)filters.get(i);if (gatewayFilter instanceof Ordered) {ordered.add(gatewayFilter);} else {// 从1开始递增生成Order值ordered.add(new OrderedGatewayFilter(gatewayFilter, i + 1));}}return ordered;}
请求网关时,org.springframework.cloud.gateway.handler.FilteringWebHandler会将路由中的过滤器和全局过滤器合并封装排序,生成完整的过滤器链。
public Mono<Void> handle(ServerWebExchange exchange) {Route route = (Route)exchange.getRequiredAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);List<GatewayFilter> gatewayFilters = route.getFilters();List<GatewayFilter> combined = new ArrayList(this.globalFilters);// 将路由中的过滤器集合添加到全局过滤器集合combined.addAll(gatewayFilters);// 排序算法AnnotationAwareOrderComparator.sort(combined);if (logger.isDebugEnabled()) {logger.debug("Sorted gatewayFilterFactories: " + combined);}return (new FilteringWebHandler.DefaultGatewayFilterChain(combined)).filter(exchange);}
debug调试
通过debug调试,排序前的过滤器顺序,可以看出路由中配置的GatewayFilter类型过滤器是追加在GlobalFilter过滤器集合后面,并且可以看出GatewayFilter类型的过滤器Order值是1、2、3。
排序后,按照Order值排序,GlobalFilter类型过滤器的Order值相同时,按文件名排序,GatewayFilte和GlobalFilterr类型过滤器的Order值相同时也是排在GlobalFilter下面。
所以最终的执行顺序是
可以自己在项目中debug调试,查看org.springframework.cloud.gateway.handler.FilteringWebHandler#handle中的combined顺序,即为过滤器执行顺序。
Spring Cloud Gateway 过滤器执行顺序原理分析相关推荐
- 从0开始构建你的api网关--Spring Cloud Gateway网关实战及原理解析
API 网关 API 网关出现的原因是微服务架构的出现,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题 ...
- Spring Cloud Gateway 过滤器详解
一.概述 Spring Cloud Gateway根据作用范围划分为:GatewayFilter和GlobalFilter 1.filter的作用和生命周期 由filter工作流程点,可以知道filt ...
- gateway 过滤器执行顺序_Gateway网关源码解析—路由(1.1)之RouteDefinitionLocator一览...
一.概述 本文主要对 路由定义定位器 RouteDefinitionLocator 做整体的认识. 在 <Spring-Cloud-Gateway 源码解析 -- 网关初始化> 中,我们看 ...
- Spring Cloud Gateway配置详解-过滤器
Spring Cloud Gateway-过滤器 本节将为大家详细介绍Spring Could Gateway 内置过滤器相关内容. Spring Cloud Gateway 过滤器为大家提供了修改特 ...
- Spring Cloud Gateway之Predict篇
Spring Cloud gateway工作流程 在之前的文章的Spring Cloud GateWay初体验中,大家已经对Spring Cloud Gateway的功能有一个初步的认识,网关作为一个 ...
- 微服务网关spring cloud gateway入门详解
1.API网关 API 网关是一个处于应用程序或服务( REST API 接口服务)之前的系统,用来管理授权.访问控制和流量限制等,这样 REST API 接口服务就被 API 网关保护起来,对所有的 ...
- Spring Cloud Gateway 之Predict篇
转载请标明出处: http://blog.csdn.net/forezp/article/details/84926662 本文出自方志朋的博客 个人博客纯净版:https://www.fangzhi ...
- 三分钟了解Spring Cloud Gateway路由转发之自动路由
文章目录 一.前言 二.路由配置 1. 静态路由 2. 动态路由 3. 自动路由 三.Spring Cloud Gateway 是如何实现动态路由 工作原理 源码解析 路由转发原理 路由转发源码解析 ...
- Spring Cloud Gateway远程代码执行CVE-2022-22947漏洞分析及复现
0x01 漏洞描述 Spring Cloud Gateway 是基于 Spring Framework 和 Spring Boot 构建的 API 网关,它旨在为微服务架构提供一种简单.有效.统一的 ...
最新文章
- C++中的重难点看这一篇就够了
- java util logging_简单日志记录,使用java.util.logging
- 动态规划入门 合并石子 COGS1660 石子合并
- Integer的缓存机制
- [转载] Python基础:什么是字符串?字符串是用来做什么的?
- 企业管理--盖洛普Q12测评法
- 计算机档案管理系统论文,学生档案管理系统计算机论文.doc
- Aspect Level Sentiment Classification with Deep Memory Network
- 身份证号码中间位数隐藏
- Excel制作工资条
- BIOS怎么开启UEFI模式|电脑设置UEFI启动的方法
- vue安装使用v-chart时报错解决方案
- 力扣:647. 回文子串
- vscode 代码格式化及快捷键
- Percona XtraDB Cluster(PXC)——架构原理
- 国家标准计算机软件测试文档范文,软件测试相关国家标准.doc
- 谈谈 Redis 的过期策略
- 维克森林大学计算机科学专业好不好,维克森林大学商业分析硕士怎么样?
- dnf如何快速拾取物品_dnf一键捡物品的方法步骤技巧
- 小小Python爬虫(0)
热门文章
- C# Remoting(RPC调用)
- 什么是业务逻辑层(业务层)及业务逻辑层(业务层)的功能
- DWORD类型与16进制字符串之间的相互转换
- c语言dword转float,vc中float与DWORD的互想转换实现代码
- 汇编语言(王爽) 课程设计一
- 【如何选到好策略做投资组合?】选股策略太多不知道用哪个?教你几行神奇代码来挑选
- 基于vue-strap的轮播组件,下载即用
- MyCat:第二章:Mycat前世今生,java运行原理图
- 聚观早报 | 支付宝支持向微信转账;​Win12 系统或新增灵动岛
- IDEA开发工具的安装(大学生作业)