Spring-Cloud-Gateway的过滤器的执行顺序问题
过滤器的种类
Spring-Cloud-Gateway中提供了3种类型的过滤器,分别是:路由过滤器、Default过滤器和Global过滤器。
路由过滤器和Default过滤器
路由过滤器和Default过滤器本质上是同一种过滤器,只不过作用范围不一样,路由过滤器只针对单个路由起作用,而Default过滤器对整个路由表中所有的路由都起作用,这2个过滤器的处理逻辑都是Spring已经内置好的,无须开发人员来写代码,只需要做一下配置即可。
Spring已经提供好了30多种这样的过滤器,比如:
- AddRequestHeader
- AddRequestParameter
- StripPrefix
- …
这些过滤器都是org.springframework.cloud.gateway.filter.GatewayFilter的子类,每一种过滤器都是由一种过滤器工厂来生成的,比如: - AddRequestHeaderGatewayFilterFactory生成AddRequestHeader的过滤器
- AddRequestParameterGatewayFilterFactory生成AddRequestParameter的过滤器
- StripPrefixGatewayFilterFactory生成StripPrefix的过滤器
Global过滤器
Global过滤器与上面两个不一样,Global过滤器需要开发人员自己来实现业务逻辑,并且它是org.springframework.cloud.gateway.filter.GlobalFilter的子类。
过滤器的执行顺序
如果是Global过滤器,可以让Global过滤器实现org.springframework.core.Ordered接口来设置过滤器的顺序,但是这里注意@org.springframework.core.annotation.Order这个注解是不起作用的。
如果是路由过滤器和Default过滤器,他们的处理逻辑是Spring内置的,因此,他们的顺序是按照声明的顺序,从1开始递增的,比如:
routes:- id: userserviceuri: lb://userservicepredicates:- Path=/user/**filters:- AddRequestHeader=RouterFilter1, router1- AddRequestHeader=RouterFilter2, router2default-filters:- AddRequestHeader=DefaultFilter1, default1- AddRequestHeader=DefaultFilter1, default2
以上的配置种,router1的order是1,router2的order是2,default1的order是1,default2的order是2,也就是说按照他们声明的顺序,从1往上递增。
那么,当系统中同时存在这么多过滤器的时候,他们的执行顺序是什么样子的呢?比如,我现在同时定义了GlobalFilter1和GlobalFilter2,还有配置了router1、router2、default1、default2的时候:
@Component
public class GlobalFilter1 implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {log.info("============global1=============");return chain.filter(exchange);}@Overridepublic int getOrder() {return 2;}
}
还有GlobalFilter2:
@Component
public class GlobalFilter2 implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {log.info("============global2=============");return chain.filter(exchange);}@Overridepublic int getOrder() {return 1;}
}
只需要在org.springframework.cloud.gateway.handler.FilteringWebHandler#handle()上打断点看一下即可:
@Override
public Mono<Void> handle(ServerWebExchange exchange) {Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);// 拿到所有的路由过滤器,包含了Default过滤器List<GatewayFilter> gatewayFilters = route.getFilters();// 拿到所有的Global过滤器List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);// 先添加的Global过滤器,然后再添加的路由过滤器combined.addAll(gatewayFilters);// TODO: needed or cached?AnnotationAwareOrderComparator.sort(combined);if (logger.isDebugEnabled()) {logger.debug("Sorted gatewayFilterFactories: " + combined);}// 在这一行打断点,查看下combined之后的内容return new DefaultGatewayFilterChain(combined).filter(exchange);
}
如下:

从源码种可以看出来,是先添加的Global过滤器,然后再添加的路由过滤器,从上面的截图也可以看出来,GlobalFilter2排在最前面,后面依次是default1、router1、GlobalFilter1、default2、router2。
可以继续在org.springframework.cloud.gateway.filter.factory.AddRequestHeaderGatewayFilterFactory#filter()方法和GlobalFilter上打断点,看一下后续的执行顺序。
因此,这些过滤器的执行顺序首先是根据order进行的排序,如果order相同,优先级是Global>Default>Router。
3种过滤器的类型都不一样为啥可以在一块进行排序?
Global过滤器是org.springframework.cloud.gateway.filter.GlobalFilter的子类,但是路由过滤器和Default过滤器是org.springframework.cloud.gateway.filter.GatewayFilter的子类,他们为啥可以放在一个集合中进行排序呢?
还是看org.springframework.cloud.gateway.handler.FilteringWebHandler这个类,它里面有一个loadFilters()方法:
private static List<GatewayFilter> loadFilters(List<GlobalFilter> filters) {return filters.stream().map(filter -> {// 把GlobalFilter适配成了GatewayFilterAdapterGatewayFilterAdapter gatewayFilter = new GatewayFilterAdapter(filter);// 并且这里计算顺序的时候,只是从Ordered接口取的if (filter instanceof Ordered) {int order = ((Ordered) filter).getOrder();return new OrderedGatewayFilter(gatewayFilter, order);}return gatewayFilter;}).collect(Collectors.toList());
}
// GatewayFilterAdapter 就实现了GatewayFilter接口
private static class GatewayFilterAdapter implements GatewayFilter {private final GlobalFilter delegate;GatewayFilterAdapter(GlobalFilter delegate) {this.delegate = delegate;}@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {return this.delegate.filter(exchange, chain);}
}
从上面的源码可以看出来,gateway框架在启动的时候,会把系统中所有的GlobalFilter适配成GatewayFilterAdapter ,而GatewayFilterAdapter 是实现了GatewayFilter 接口的,因此GlobalFilter也就适配成了GatewayFilter ,因此他们是可以放到一个集合进行排序的。同时可以看到,在获取GlobalFilter的order时候,只是使用Ordered接口并没有使用@Order注解。
结论
- Global过滤器的顺序是由
Ordered接口来定义,@Order不起作用。 - 路由过滤器和Default过滤器的顺序是按照声明的顺序,从1开始递增
- 所有的Global过滤器、路由过滤器、Default过滤器最终会放到一个集合中按照order大小进行排序
- 如果order值一样,优先就是Global过滤器>Default过滤器>路由过滤器
ps:以上测试结论基于<spring-cloud.version>Hoxton.SR10</spring-cloud.version>
相关文章:
Spring-Cloud-Gateway的过滤器的执行顺序问题
过滤器的种类 Spring-Cloud-Gateway中提供了3种类型的过滤器,分别是:路由过滤器、Default过滤器和Global过滤器。 路由过滤器和Default过滤器 路由过滤器和Default过滤器本质上是同一种过滤器,只不过作用范围不一样,路由过滤器…...
Android性能优化的底层逻辑
前言性能优化仿佛成了每个程序员开发的必经之路,要想出人头地,与众不同,你还真需要下点功夫去研究Android的性能优化,比如说,从优化应用启动、UI加载、再到内存、CPU、GPU、IO、还有耗电等等,当你展开一个方…...
Gradle+SpringBoot多模块开发
关于使用Gradle结合SpringBoot进行多模块开发。 本来是打算使用buildSrc之类的,但是感觉好像好麻烦,使用这种方法就可以实现,没必要采用其他的。 我不怎么会表述,可能写的跟粑粑一样,哈哈哈哈 这是我的项目地址。 存在…...
Qt 之 emit、signals、slot的使用
本文福利,莬费领取Qt开发学习资料包、技术视频,内容包括(C语言基础,Qt编程入门,QT信号与槽机制,QT界面开发-图像绘制,QT网络,QT数据库编程,QT项目实战,QSS&am…...
每日学术速递3.6
Subjects: cs.CV 1.Multi-Source Soft Pseudo-Label Learning with Domain Similarity-based Weighting for Semantic Segmentation 标题:用于语义分割的基于域相似性加权的多源软伪标签学习 作者:Shigemichi Matsuzaki, Hiroaki Masuzawa, Jun Miura …...
C# 将对象转换成字节数组(二进制数据)
在将自定义对象或者数组等这样的数据存储到数据库时往往需要转换成二进制字节,尤其是在一些O/RM数据库框架中,下面是转换的函数,一个是将对象转换成二进制字节数组,另一个是将从数据库中读取的二进制流转换成程序中的对象。 这里…...
巾帼绽芬芳 一起向未来(下篇)
编者按:为了隆重纪念纪念“三八”国际妇女节113周年,快来与你全方位、多层次分享交流“三八”国际妇女节的前世今生。分上篇(节日简介、节日发展和节日意义)、中篇(节日活动宗旨和世界各国庆祝方式)和下篇&…...
代码还原小试牛刀(一):魔改的MD5
一、目标 2023年了,MD5已经是最基础的签名算法了,但如果你还只是对输入做了简单的MD5,肯定会被同行们嘲笑。加点盐(salt)是一种基本的提升,但在这个就业形势严峻的时代,仅仅加盐肯定不够了。 …...
6. 找大佬
1 题目描述 找大佬成绩20开启时间2021年09月24日 星期五 18:00折扣0.8折扣时间2021年11月15日 星期一 00:00允许迟交否关闭时间2021年11月23日 星期二 10:00 众所周知,每个专业里都会有一些大佬隐藏在人群里。软件工程专业也是如此。今天的你就像从人群中找到真正的…...
【CSS】标签显示模式 ① ( 标签显示模式 | 块级元素 )
文章目录一、标签显示模式 ( 块级元素 | 行内元素 )二、块级元素1、块级元素简介2、块级元素特点3、文字块级元素4、代码示例一、标签显示模式 ( 块级元素 | 行内元素 ) 标签显示模式 : 指的是 标签显示的方式 , 标签类型有很多 , 不同的情景使用不同类型的标签 ; 块级元素 : …...
hive真实表空间大小统计
1. 问题 如果是采用hdfs上传加载的表、或者是flume直接写hdfs的表空间通常看hive的属性是不准确的。 2. 思路 为了使结果更精确,我们直接使用linux下命令统计hive仓库目录下的每个表对应的文件夹目录占用空间的大小。 3. 解决方法 这里建立三层表结构 ods: 原始…...
微信小程序引入Vant UI步骤
官方文档教程 1、通过 npm 安装 # 通过 npm 安装 npm i vant/weapp -S --production# 通过 yarn 安装 yarn add vant/weapp --production# 安装 0.x 版本 npm i vant-weapp -S --production2、修改 app.json 将 app.json 中的 “style”: “v2” 去除,小程序的新…...
【震撼发布】《致敬未来的攻城狮计划》| 文末赠书3本
《致敬未来的攻城狮计划》—— 文末有福利 摘要: 一个崭新的计划,寻找那群有志于向嵌入式发展的未来工程师! 文章目录1 活动计划初衷2 活动计划形式3 活动计划收获4 活动计划要求5 活动计划时间6 活动计划致谢7 活动计划特别说明8 温馨提示9 …...
8.装饰者模式
目录 简介 角色组成 实现步骤 1. 新建 Log.class,添加如下代码 2. 新建 Log4j.class,继承 Log.class,并实现 record() 方法 3. 新建 Decorator.class,继承 Log.class 4. 新建 Log4jDecorator.class,继承 Decorat…...
GIT基础常用命令-1 GIT基础篇
git基础常用命令-1 GIT基础篇1.git简介及配置1.1 git简介1.2 git配置config1.2.1 查看配置git config1.2.2 配置设置1.2.3 获取帮助git help2 GIT基础常用命令2.1 获取镜像仓库2.1.1 git init2.1.2 git clone2.2 本地仓库常用命令2.2.1 git status2.2.2 git add2.2.3 git diff2…...
华为OD机试题,用 Java 解【数列描述】问题
华为Od必看系列 华为OD机试 全流程解析+经验分享,题型分享,防作弊指南)华为od机试,独家整理 已参加机试人员的实战技巧华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典使用说明 参加华为od机试,一定要注意不…...
2022掉队的“蔚小理”,按下了兔年加速键
配图来自Canva可画 进入2023年,各大车企又展开了新一轮的“竞速”。尽管1月份汽车整体销量出现了“阴跌”,但从各路车企发布的销量目标来看,车企对于2023依旧保持着较高的信心和预期。在一众车企中,以“蔚小理”为代表的新势力们…...
【NLP相关】attention的代码实现
❤️觉得内容不错的话,欢迎点赞收藏加关注😊😊😊,后续会继续输入更多优质内容❤️👉有问题欢迎大家加关注私戳或者评论(包括但不限于NLP算法相关,linux学习相关,读研读博…...
凌恩生物资讯
凌恩生物转录组项目包含范围广,项目经验丰富,人均10年以上项目经验,其中全长转录组测序研究基因结构已经成为发文章的趋势,研究物种包括高粱、玉米、拟南芥、鸡、人和小鼠、毛竹、棉花等。凌恩生物提供专业的全长转录组测序及分析…...
Leetcode 148. 排序链表(二路归并)
题目: 给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。 解法一: 递归解法,自顶向下 链表版二路归并排序(升序,递归版),稳定排序 时间复杂度…...
避坑指南:OpenBMI运动想象实验中的‘跨被试’与‘不跨被试’到底怎么选?
避坑指南:OpenBMI运动想象实验中的‘跨被试’与‘不跨被试’到底怎么选? 当你第一次接触OpenBMI工具箱进行运动想象(Motor Imagery, MI)实验时,最令人困惑的决策之一就是如何选择数据划分策略。是采用**跨被试…...
智能视频PPT提取:从动态内容到静态文档的高效转化方案
智能视频PPT提取:从动态内容到静态文档的高效转化方案 【免费下载链接】extract-video-ppt extract the ppt in the video 项目地址: https://gitcode.com/gh_mirrors/ex/extract-video-ppt 场景痛点:视频内容提取的三大核心挑战 如何从90分钟的…...
告别手动调参!用Simulink扫频法+PID Tuner,10分钟搞定升降压电路的PI控制器设计
10分钟自动化PI设计:Simulink扫频与PID Tuner在升降压电路中的实战技巧 电力电子工程师们对这样的场景一定不陌生:面对一个全新的升降压电路拓扑,为了获得稳定的输出电压,不得不花费数小时甚至数天时间反复调整PI控制器的参数。传…...
低成本GPU算力优化:cv_unet_image-colorization显存占用实测与调优
低成本GPU算力优化:cv_unet_image-colorization显存占用实测与调优 1. 项目背景与价值 在数字影像修复领域,AI图像上色技术正成为越来越受欢迎的工具。基于UNet架构的cv_unet_image-colorization模型,通过深度学习算法能够智能识别黑白图像…...
2026 Global Ion Exchange Resin Systems Market Trends:关税扰动下的工程水处理系统重构与产业链迁移逻辑
观点 离子交换树脂系统的竞争核心,已经不再是“树脂材料”,而是“系统工程能力 供应链组织能力”。 2026年关税变量的加入,本质上正在把这个行业从“化工材料赛道”,推向“工程系统全球制造网络”的复合竞争阶段。一、这不是树脂…...
Pixel Couplet Gen入门必看:Streamlit Components封装像素春联React组件
Pixel Couplet Gen入门必看:Streamlit Components封装像素春联React组件 1. 项目介绍 Pixel Couplet Gen是一款基于ModelScope大模型驱动的创意春联生成器。与传统春联设计不同,它采用了独特的8-bit像素游戏风格,将中国传统春节元素与复古电…...
Kotlin 2.3.20 正式发布!解构声明不怕写反了
val (email, username) user你确定没写反? 如果 User 的属性顺序是 (username, email),恭喜你,这段代码已经悄悄埋了一个 bug。更可怕的是,两个属性都是 String 类型,编译器不会报任何错误。 Kotlin 2.3.20 刚刚发布…...
Linux服务器日志爆满?5个实用命令快速定位并清理大日志文件
Linux服务器日志爆满?5个实用命令快速定位并清理大日志文件 当服务器磁盘空间告急时,日志文件往往是罪魁祸首。作为系统管理员,我们需要快速定位问题并安全清理,避免服务中断。本文将分享5个核心命令的组合使用技巧,帮…...
避坑指南:PyTorch QAT模型部署时,你的推理结果为什么对不上?从量化参数到计算细节的排查思路
PyTorch QAT模型部署实战:量化推理结果异常的全链路诊断手册 当你的量化感知训练(QAT)模型在部署环节突然"翻车"——推理结果与训练时相差甚远,这种场景就像精心调制的咖啡在最后一刻被打翻。本文将带你深入量化模型的黑…...
Git开源贡献全指南:从入门到精通
开源项目Git贡献全流程拆解 理解开源项目贡献的基本概念 开源项目的定义与意义Git在开源协作中的核心作用常见的开源贡献类型(代码、文档、测试等) 准备开发环境 安装Git并完成基础配置(用户名、邮箱、SSH密钥)注册GitHub/GitLab等…...
