Spring-Cloud-Gateway的过滤器的执行顺序问题

news2024/11/16 8:50:14

过滤器的种类

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: userservice
          uri: lb://userservice
          predicates:
            - Path=/user/**
          filters:
            - AddRequestHeader=RouterFilter1, router1
            - AddRequestHeader=RouterFilter2, router2
      default-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 {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("============global1=============");
        return chain.filter(exchange);
    }
    @Override
    public int getOrder() {
        return 2;
    }
}

还有GlobalFilter2:

@Component
public class GlobalFilter2 implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("============global2=============");
        return chain.filter(exchange);
    }
    @Override
    public 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适配成了GatewayFilterAdapter
		GatewayFilterAdapter 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;
	}
	@Override
	public 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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/390998.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【水下图像增强】Enhancing Underwater Imagery using Generative Adversarial Networks

原始题目Enhancing Underwater Imagery using Generative Adversarial Networks中文名称使用 GAN 增强水下图像发表时间2018年1月11日平台ICRA 2018来源University of Minnesota, Minneapolis MN文章链接https://arxiv.org/abs/1801.04011开源代码官方&#xff1a;https://gith…

Linux 进程:exec函数簇

目录&#xff08;1&#xff09;execl&#xff08;2&#xff09;execlp&#xff08;3&#xff09;execle&#xff08;4&#xff09;execv&#xff08;5&#xff09;execvp&#xff08;6&#xff09;execve在进程控制中提到&#xff0c;子进程的最大价值在于程序替换&#xff0c;…

Android动态权限获取官方实现之easypermission

Android动态权限获取官方实现之easypermission Android 6.0之后&#xff0c;基于用户隐私和安全考虑&#xff0c;敏感权限都开始采用动态运行时机制获取&#xff0c;于是就出现如果你不向用户申请权限&#xff08;弹窗&#xff0c;用户选择&#xff09;&#xff0c;有些功能就…

Flutter Android 打包保姆式全流程 2023 版

大家好&#xff0c;我是 17。 为什么要写这篇文章呢&#xff1f;对于一没有 android 开发经验&#xff0c;从未有过打包经历的新人来说&#xff0c;要想成功打包&#xff0c;是很困难的。因为受到的阻碍太多&#xff0c;是完全陌生的领域&#xff0c;几乎是寸步难行。如果有老…

hive真实表空间大小统计

1. 问题 如果是采用hdfs上传加载的表、或者是flume直接写hdfs的表空间通常看hive的属性是不准确的。 2. 思路 为了使结果更精确&#xff0c;我们直接使用linux下命令统计hive仓库目录下的每个表对应的文件夹目录占用空间的大小。 3. 解决方法 这里建立三层表结构 ods: 原始…

linux入门---粘滞位

为什么会有粘滞位 一台服务器有很多人使用&#xff0c;每个人在机器上都会有一个家目录&#xff0c;在家目录里可以实现自己想要的操作&#xff0c;但是有时候我们需要一个公共路径来完成一些操作&#xff0c;比如说资料分享产生临时文件的增删查改等等&#xff0c;这就好比我…

数据结构和算法学习记录——删除有序数组中的重复项、合并两个有序数组

去重删除有序数组中的重复项题目来自&#xff1a;https://leetcode.cn/problems/remove-duplicates-from-sorted-array/description/题目描述给你一个 升序排列 的数组 nums &#xff0c;请你原地删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff0c;返回删除后数…

leetcode 71~80 学习经历

leetcode 71~80 学习经历71. 简化路径72. 编辑距离73. 矩阵置零74. 搜索二维矩阵75. 颜色分类76. 最小覆盖子串77. 组合78. 子集79. 单词搜索80. 删除有序数组中的重复项 II小结71. 简化路径 给你一个字符串 path &#xff0c;表示指向某一文件或目录的 Unix 风格 绝对路径 &am…

2023年再不会 IOC 源码,就要被淘汰了

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱敲代码的小黄&#xff0c;独角兽企业的Java开发工程师&#xff0c;CSDN博客专家&#xff0c;阿里云专家博主&#x1f4d5;系列专栏&#xff1a;Java设计模式、数据结构和算法、Kafka从入门到成神、Kafka从成神到升仙…

详细聊TTL电平、RS232接口和RS485接口

TTL电平 TTL&#xff08;Transistor-Transistor Logic&#xff09;是一种数字电平标准&#xff0c;常用于数字电子设备之间的数据传输。 TTL使用0V表示逻辑0&#xff0c;使用5V表示逻辑1&#xff0c;因此TTL信号的电平比较容易理解和处理。TTL信号传输距离较短&#xff0c;通…

文件服务设计

一、需求背景 文件的上传、下载功能是软件系统常见的功能&#xff0c;包括上传文件、下载文件、查看文件等。例如&#xff1a;电商系统中需要上传商品的图片、广告视频&#xff0c;办公系统中上传附件&#xff0c;社交类系统中上传用户头像等等。文件上传下载大致流程为&#…

【Java诊断工具】Arthas使用指南

文章目录一、简介二、解决什么问题 & 适用场景解决问题&#xff1a;适应场景&#xff1a;三、安装&启动四、相关命令五、来自天边的"海市蜃楼"六、结束一、简介 Arthas 是Alibaba开源的Java诊断工具。安装在系统所在服务器。通过全局视角实时查看应用 load、…

人工智能论文术语集39

Resume 简历&#xff08;但在AI领域一般指&#xff1a;复位&#xff09;Perform arithmetic operations 执行算数操作performance measurement and improvement techniques 性能测试和改进技术draw stuff with your mouse 用鼠标画东西the Color Palette 调色板high dynamic ra…

41 42Ping-Pong操作

提高电路吞吐率的结构——Ping-Pong操作 1.Ping-Pong操作原理 作用&#xff1a;为了让两个不匹配的模块进行对接&#xff0c;并且在对接的过程中让这两个模块能够同时工作&#xff0c;提高数据处理的吞吐率&#xff08;也称throughput效能&#xff09; 常见的不匹配&#xff1…

Semaphore 源码解读

一、Semaphore Semaphore 通过设置一个固定数值的信号量&#xff0c;并发时线程通过 acquire() 获取一个信号量&#xff0c;如果能成功获得则可以继续执行&#xff0c;否则将阻塞等待&#xff0c;当某个线程使用 release() 释放一个信号量时&#xff0c;被等待的线程如果可以成…

idea初学笔记

注:初学需安装idea专业版&#xff0c;方便学习使用idea运行内存配置从eclipse工具开发 转 idea工具开发&#xff0c;可设置idea快捷键同eclipse快捷键 file -> Settings -> Keymap -> 选择Eclipse -> OK设置idea项目整体编码格式file -> Settings -> Editor …

mysql五种索引类型---实操版本

背景 最近学习了Mysql的索引&#xff0c;索引对于Mysql的高效运行是非常重要的&#xff0c;正确的使用索引可以大大的提高MySql的检索速度。通过索引可以大大的提升查询的速度。不过也会带来一些问题。比如会降低更新表的速度&#xff08;因为不但要把保存数据还要保存一下索引…

Linux【进程理解】

文章目录Linux【进程理解】一、冯诺依曼体系结构二、操作系统OS1.深入理解操作系统2.深入理解系统调用和库函数四、 进程&#xff08;一&#xff09;描述进程-PCB&#xff08;二&#xff09;组织进程和查看进程&#xff08;三&#xff09;通过系统调用创建进程-fork初识&#x…

【python】XML格式文件读写详解

注&#xff1a;最后有面试挑战&#xff0c;看看自己掌握了吗 文章目录XML介绍格式XML与AJAX与HTML区别联系生成XML文件案例用SAX模块处理XML用DOM模块处理XML&#x1f338;I could be bounded in a nutshell and count myself a king of infinite space. 特别鸣谢&#xff1a;…

三:BLE协议架构简介

低功耗蓝牙体系整体架构说明1. PHY(物理层)2. LL(链路层)3. HCI(主机与控制器通信接口)4. L2CAP(逻辑链路控制及适配协议)5. ATT(属性协议)6. GATT(通用属性规范)7. GAP(通用访问规范)8. SM(安全管理)整体架构说明 架构层说明PHY1. 物理层2. 控制射频的发送和接收LL1. 链路层2.…