Servlet-Filter 执行顺序测试

news2025/3/6 21:50:27

Servlet-Filter 执行顺序测试

对于 web.xml 文件注册过滤器这里就不多说了,就是谁声明的早,谁先被调用。因为在上面的过滤器信息最先被扫描到。

模型抽象

为了便于在实践中使用,结合部分底层原理,我们可以对 Filter 链的执行做一下抽象。

我们有一个初始容量为 0 的队列,该队列中有一个 insertPos(以下简写为 ips,初始值为-1) 的属性,用来指示上一个 isMatchAfter 值为 false 的 filter 的添加位置(下标)。当尝试 addMappingForUrlPattern 时,判断当前 Filter 的 isMatchAfter 的属性值:

  • 若 isMatchAfter 值为 true,则直接将元素添加至队尾;
  • 若 isMatchAfter 值为 false,则将该元素添加到下标为 insertPos + 1 的位置,即插入到上一个 isMatchAfter 为 false 的 filter 的下一个位置,随后将 ips ++;

我们举例说明这个模型的使用:
true, true, false, false 为例,那么假如的顺序为:

  • 加入链尾。01, ips 为 -1;
  • 加入链尾。01 -> 02,ips 为 -1;
  • 加入到 ips + 1 = 0 的位置。03 -> 01 -> 02,ips 为 0;
  • 加入到 ips + 1 = 1 位置。03 -> 04 -> 01 -> 02,ips 为 1;

若顺序为 false, false, true, true

  • 加入 ips + 1 = 0的位置。01,ips 为 0;
  • 加入到 ips + 1 = 1 位置。01 -> 02,ips 为 1;
  • 加入链尾。01 -> 02 -> 03
  • 加入链尾。01 -> 02 -> 03 -> 04

所以按照模型,在 web.xml 中注册的 filter 默认 isMatchAfter 的值就全部为 true 或者 false。

测试环境

  • tomcat 10.1.17
  • servlet-api: Jakarta-servlet-api: 6.0.0, Jakarta-annotaion: 2.0.0
  • Java 17

使用 @WebFilter 注解

结论

如果使用注解,那么 Filter 的顺序就取决于文件的组织形式,即按照文件夹的排列的顺序来定义 filter 的顺序。

而 Idea 的文件的组织形式都是按照文件名进行排序的,所以如果用模型来解释,以这种方式注册的 filter,isMatchAfter 的值都为 true 或者 false。谁先被扫描到,谁就先加入队列。

过程

同一文件夹内

若文件的组织如下图所示:
image.png

@WebFilter(value = "/*", filterName = "03")
@Slf4j
public class _01 implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        log.info("01 filter....");
        chain.doFilter(request, response);
    }
}


@WebFilter(value = "/*", filterName = "02")
@Slf4j
public class _02 implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        log.info("02 filter....");
        chain.doFilter(request, response);
    }
}

@Slf4j
@WebFilter(value = "/*", filterName = "01")
public class _03 implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        log.info("03 filter....");
        chain.doFilter(request, response);
    }
}

执行结果为(经过多次请求地址 localhost:8080,仍然为这一结果):

2023-12-22 11:29:22.871 INFO  [http-nio-8080-exec-1]  c.y.w.fiter._01 01 filter....
2023-12-22 11:29:22.874 INFO  [http-nio-8080-exec-1]  c.y.w.fiter._02 02 filter....
2023-12-22 11:29:22.874 INFO  [http-nio-8080-exec-1]  c.y.w.fiter._03 03 filter....
2023-12-22 11:29:23.516 INFO  [http-nio-8080-exec-2]  c.y.w.fiter._01 01 filter....
2023-12-22 11:29:23.516 INFO  [http-nio-8080-exec-2]  c.y.w.fiter._02 02 filter....
2023-12-22 11:29:23.516 INFO  [http-nio-8080-exec-2]  c.y.w.fiter._03 03 filter....
2023-12-22 11:29:23.732 INFO  [http-nio-8080-exec-3]  c.y.w.fiter._01 01 filter....
2023-12-22 11:29:23.732 INFO  [http-nio-8080-exec-3]  c.y.w.fiter._02 02 filter....
2023-12-22 11:29:23.732 INFO  [http-nio-8080-exec-3]  c.y.w.fiter._03 03 filter....


不同文件夹下

文件夹的组织如下:
image.png

类信息不变。

执行结果为:
image.png


如果我们把类名进行修改,但是类信息不变,如下:
image.png

执行结果为:
image.png

可以看到,仍然是按照从上到下的顺序进行执行的,所以,由以上实验可以得到 WebFilter 定义的注解与类名和 filterName 属性都无关。

总结

可见,在 idea 测试环境下,若把所有的 Filter 组织在一个文件夹下,那么 Filter 的执行顺序是与类名有关的。因为,idea 的文件组织是默认按照名称进行排序的(与 windows 的默认文件排序方式无关)。

也就是说,过滤器的执行顺序只与谁先被扫描到(谁先被加入到过滤器链条)有关(Servlet-api 底层的定义的是 LinkedHashSet 结构来存储过滤器链的)。所以,我们不推荐使用注解的方法定义过滤器链

ServletContext 动态注册 Filter

对于这种情况,网上有很多种说法,最可信的(看起来对的)说法是,按照加入 ServletContext 的顺序为执行顺序,这种说法是很有道理的。因为不论是扫描 xml 文件加入 Filter 还是扫描文件夹假如 Filter,最后都将这个过滤链加入了 ServletContext。

倘若我们嫌分析源码麻烦,那么做一个实验去验证是最为经济的做法了。

我们对上次的实验的类进行保留,只是去除 WebFilter 注解。然后尝试进行动态注册。

结论

  • addMappingForUrlPatterns 方法的调用决定了过滤器的顺序:
    • isMatchAfter 全部为 true 时,方法的调用顺序决定了过滤器的执行顺序,并且为正相关(先调用先执行);
    • isMatchAfter 全部为 false 时,与上一种情况相同;
    • 当有一个 filter 的 isMatchAfter 属性为 true 或者 false 的时候,

不同文件夹下

image.png

对照实验

我们设置的测试代码为:

@Slf4j
@WebListener
public class ContainerInitializer implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        ServletContext ctx = sce.getServletContext();
        FilterRegistration.Dynamic filter_01 = ctx.addFilter("01", _01.class);
        FilterRegistration.Dynamic filter_02 = ctx.addFilter("02", _02.class);
        FilterRegistration.Dynamic filter_03 = ctx.addFilter("03", _03.class);
        filter_01.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
        filter_02.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
        filter_03.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
    }
}

最后的执行结果为,重复四次实验(访问 localhost:8080):

可以看到,顺序为我们注册到 ServletContext 的顺序。请忽略后续的 log 的 message 信息,这是无关紧要的。


改变 addFilter 顺序

现在我们调换 addFilter 的顺序,从 _01 -> _02 -> _03 调整为 _02 -> _01 -> _03。其余不变,即:

		FilterRegistration.Dynamic filter_02 = ctx.addFilter("02", _02.class);
        FilterRegistration.Dynamic filter_01 = ctx.addFilter("01", _01.class);
        FilterRegistration.Dynamic filter_03 = ctx.addFilter("03", _03.class);
        // nothing changed
        

执行结果为:
image.png

发现结果不变,说明改变,addFilter 顺序行为并不能改变注册顺序。


改变 filterName

尝试改变 filterName 来试图调整顺序,即:

		FilterRegistration.Dynamic filter_01 = ctx.addFilter("03", _01.class);
        FilterRegistration.Dynamic filter_02 = ctx.addFilter("02", _02.class);
        FilterRegistration.Dynamic filter_03 = ctx.addFilter("01", _03.class);

执行结果为:
image.png

没有任何效果。


改变 addMappingForUrlPatterns 的调用
isMatchAfter 全部为 true

尝试改变 addMappingForUrlPatterns 方法的调用顺序,即:

        filter_02.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
        filter_01.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
        filter_03.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");

执行结果为:
image.png
不受到 isMatchAfter 的影响。只与调用顺序有关。

isMatchAfter 全部为 false

直接上结果:
image.png
不受到 isMatchAfter 的影响。只与调用顺序有关。

isMatchAfter 只有一个为 true

image.png

执行结果为:
image.png
为 true 的 filter 在所有 filter 之后执行。

isMatchAfter 只有一个为 false

修改源码为:
image.png

执行结果为:
image.png
可以看见,isMatchAfter 为 true 的 filter 变成了第一个执行的。

当有多个 true 和 false 时

为了测试方便,我们新增一个 filter,对代码做如下修改:
image.png

执行结果为:
image.png


调换顺序:
image.png

执行结果为:
image.png


调换顺序:
image.png

执行结果为:
image.png

全部能够执行,并且按照调用顺序执行。根据以上,规律可以进行总结了。

若一个 filter 在注册的时候,将 isMatchAfter 设置为 false,就会调换到过滤链中所有 isMatchAfter 值为 false 的下一个位置(不加入到队首);若设置为 true,就默认加载过滤链尾。

故而,在多个 true,false 混合的时候,例如以 true, true, false, false 为例,那么假如的顺序为:

  • 加入链尾。01
  • 加入链尾。01 -> 02
  • 加入链首。03 -> 01 -> 02
  • 加入链首。03 -> 04 -> 01 -> 02

若顺序为 false, false, true, true

  • 加入链首。01
  • 加入链首。01 -> 02
  • 加入链尾。01 -> 02 -> 03
  • 加入链尾。01 -> 02 -> 03 -> 04

这与我们的实验结果是一致的。

总结

在不同文件夹下,过滤器的调用顺序与结论符合。

同一文件夹下

实验结果完全相同。这里的实验过程,限于篇幅就略过了。

总结

在同一文件夹下,过滤器的调用顺序与结论符合。

总结

动态注册过滤器的执行顺序只与 addMappingForUrlPatterns 方法的调用顺序和该方法的参数 isMatchAfter 有关。与文件夹,文件名,filterName 无关。

总结

实验结果完全契合模型。实际上,结合 tomcat 的源码,tomcat 只不过是将模型的队列用数组实现了而已。

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

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

相关文章

【3D生成与重建】SSDNeRF:单阶段Diffusion NeRF的三维生成和重建

系列文章目录 题目:Single-Stage Diffusion NeRF: A Unified Approach to 3D Generation and Reconstruction 论文:https://arxiv.org/pdf/2304.06714.pdf 任务:无条件3D生成(如从噪音中,生成不同的车等)、…

PlatEMO UI 界面

🎉 博主相信: 有足够的积累,并且一直在路上,就有无限的可能!!! 👨‍🎓个人主页: 青年有志的博客 💯 Github 源码下载:https://github.…

【快速开发】使用SvelteKit

自我介绍 做一个简单介绍,酒架年近48 ,有20多年IT工作经历,目前在一家500强做企业架构.因为工作需要,另外也因为兴趣涉猎比较广,为了自己学习建立了三个博客,分别是【全球IT瞭望】,【…

数据结构之进阶二叉树(二叉搜索树和AVL树、红黑树的实现)超详细解析,附实操图和搜索二叉树的实现过程图

绪论​ “生命有如铁砧,愈被敲打,愈能发出火花。——伽利略”;本章主要是数据结构 二叉树的进阶知识,若之前没学过二叉树建议看看这篇文章一篇掌握二叉树,本章的知识从浅到深的对搜索二叉树的使用进行了介绍和对其底层…

uniapp H5项目使用ucharts的Echart组件方式创建圆环

问题:没有报错但是图表不出来 【 调试了半天圆环图表没有不出来。是因为没有明示设置宽度与高度】 /* 请根据实际需求修改父元素尺寸,组件自动识别宽高 */ .charts-box { width: 100%; height: 300px; } 最终效果 先导入ucharts到项目 uniapp的项目…

hadoop集群的开启与关闭

背景 很久没完hadoopl,连怎么开启关闭都不会了qwq 1.进入安装hadoop的目录 我这里是已经进入了 2.开启集群 sbin/start-dfs.sh 3.关闭集群 sbin/stop-dfs.sh

NLP论文阅读记录 -| 对摘要评分的通用规避攻击

文章目录 前言0、论文摘要一、Introduction1.1目标问题1.2相关的尝试1.3本文贡献 二.相关工作三.本文方法3.1 问题表述3.2 对 ROUGE 和 METEOR 的白盒输入不可知攻击3.3BERTcore 上的黑盒通用触发器搜索 四 实验效果4.1数据集4.2 对比模型4.3实施细节4.4评估指标4.5 实验结果 五…

华为Harmony——ArkTs语言

文章目录 一、简单示例二、声明式UI描述创建组件无参有参数 配置属性配置事件配置子组件 三、自定义组件基本用法基本结构成员函数/变量 一、简单示例 我们以一个具体的示例来说明ArkTS的基本组成。如下图所示,当开发者点击按钮时,文本内容从“Hello Wo…

Python编写第一个APP自动化脚本,将脚本跑起来

一、前置说明 Python 使用 Appium 做 APP自动化的基本流程(Android平台): 启动 Appium Serveradb 连接设备(真机或模拟器)uiautomatorviewer 连接设备,定位元素信息使用appium-python-client库&#xff0…

基于ssm+jsp二手车估值与销售网络平台源码和论文

随着信息化时代的到来,管理系统都趋向于智能化、系统化,二手车估值与销售网络平台也不例外,但目前国内仍都使用人工管理,市场规模越来越大,同时信息量也越来越庞大,人工管理显然已无法应对时代的变化&#…

振动试验的工装夹具(GB/T 2423.43-2008)

但当试件体积较大,而且形状复杂时,这种固定方法显然很困难,这时需要制作夹具,让试件安装在夹具上然后把夹具牢固地固定在振动台面上,因此实际上夹具是试件与振动台面连接的过渡体,其功能是将振动台的振动和…

深度学习美化图片,绝对可行,美化效果挺好 DPED

一、背景 要美化生成的图片的效果,找到一个 效果如下: 二、步骤 1、python3.6环境,TensorFlow 2.0.0 2、下载代码:https://github.com/aiff22/DPEDx 3、将要增强的照片放在以下目录中,没有就新建: dpe…

亚马逊圣诞关键词怎么选?圣诞节促销活动有哪些?——站斧浏览器

亚马逊圣诞关键词怎么选 以下是在亚马逊圣诞期间利用长尾关键词的一些建议: 圣诞主题关键词:随着节日的临近,与圣诞相关的关键词搜索热度将急剧上升。在产品标题、描述、关键词等位置使用与圣诞节相关的关键词,比如“圣诞礼物”…

强烈推荐!好玩又好用的开源工具

今天来分享 7 个好玩又好用的开源工具,还可以学习项目代码! PDF Guru:通用型 PDF 文件处理工具AiEditor:面向 AI 的下一代富文本编辑器pear-rec:实用工具集,包括截图、录屏、录音、录像等Pot:划…

2024年软件测试工程师如何从功能测试转成自动化测试?

前言 接触了太多测试同行&#xff0c;由于多数同行之前一直做手工测试&#xff0c;现在很迫切希望做[<u>自动化测试</u>](javascript:;)&#xff0c;其中不乏工作5年以上的同行。 从事软件自动化测试已经近十年&#xff0c;接触过底层服务端、API 、Web、APP、H5…

鸿蒙开发之hdc命令行

一、简介 hdc&#xff08;HarmonyOS Device Connector&#xff09;是HarmonyOS为开发人员提供的用于调试的命令行工具&#xff0c;通过该工具可以在windows/linux/mac系统上与真实设备进行交互。 二、环境准备 hdc工具通过HarmonyOS SDK获取&#xff0c;存放于SDK的toolchai…

Ubuntu 常用命令之 ping 命令用法介绍

&#x1f4d1;Linux/Ubuntu 常用命令归类整理 ping命令是一种网络诊断工具&#xff0c;用于测试主机之间网络的连通性。它发送ICMP Echo Request消息到指定的网络主机&#xff0c;并等待接收ICMP Echo Reply。通过这种方式&#xff0c;我们可以知道两台主机之间的网络是否畅通…

【String str = new String(“hollis“) 创建了几个对象?】

✅典型解析 创建的对象数应该是1个或者2个。 首先要清楚什么是对象? Java是一种面向对象的语言&#xff0c;而Java对象在JVM中的存储也是有一定的结构的&#xff0c;在HotSpot虚机中&#xff0c;存储的形式就是oop-klass model&#xff0c;即ava对象模型。我们在Java代码中&am…

【计算机系统结构实验】实验2 流水线中的冲突实验

2.1 实验目的 加深对计算机流水线基本概念的理解&#xff1b; 理解MIPS结构如何用5段流水线来实现&#xff0c;理解各段的功能和基本操作&#xff1b; 加深对结构冲突/数据冲突/控制冲突的理解&#xff1b; 进一步理解解决数据冲突的方法&#xff0c;掌握如何应用定向技术来…

计算机软考有哪些科目?都考什么内容?

一、软考初级科目 1、程序员 考核内容&#xff1a;计算机相关基础知识&#xff1b;基本数据结构和常用算法&#xff1b;C程序设计语言以及C、JAVA中的一种程序设计语言。 岗位描述&#xff1a;从事软件开发和调试工作的初级技术人员。 2、网络管理员 考核内容&#xff1a;…