当前位置: 首页 > news >正文

【记录版】SpringBoot下Filter注册源码解读

SpringBoot + TomcatEmbeddedContext + Servlet + ApplicationFilterChain + Filter

背景: 在之前博客中有说明SpringBoot内嵌Web容器后,Filter及Servlet解析与注册流程的变化。将Filter实例封装成FilterRegistrationBean实例并添加到ServletContext后,到实际使用Filter完成过滤功能之前,其实中间还有一些管理流程。本文将在此背景下,继续追加描述此块逻辑。

博客内容精选:
1、Servlet请求体重复读&修改新姿势
2、根据请求获取后端接口详情
3、SpringBoot下Filter自动适配
4、Filter链式执行设计解读

一、首
先Filter相关定义经解析过存储在TomcatEmbeddedContext对象中,有三个重要变量:
1、private Map<String, FilterDef> filterDefs // 存储Filter定义元数据,如filterClass、name等
2、private final StandardContext.ContextFilterMaps filterMaps // FilterMap-匹配元数据,如String[] urlPatterns
3、private Map<String, ApplicationFilterConfig> filterConfigs // 由filterDefs可封装成ApplicationFilterConfig,核心为Filter实例

ApplicationFilterConfig(Context context, FilterDef filterDef) throws Exception{this.context = context;this.filterDef = filterDef;if (filterDef.getFilter() == null) {this.getFilter();} else {this.filter = filterDef.getFilter();context.getInstanceManager().newInstance(this.filter);this.initFilter();}
}

我们都知道Filter要发布到Servlet容器,先以FilterRegistrationBean的形式封装,因注册Bean底层接口包含ServletContextInitializer,其在onStartup(ServletContext servletContext)方法执行下注册到ServletContext中去,以下为注册代码:

// 执行入口
public final void onStartup(ServletContext servletContext) throws ServletException {..........省略.............this.register(description, servletContext);
}
// 注册入口
protected final void register(String description, ServletContext servletContext) {// 将Filter实例加入ContextD registration = this.addRegistration(description, servletContext);if (registration == null) {logger.info(StringUtils.capitalize(description) + " was not registered (possibly already registered?)");} else {// 配置Filter匹配元数据this.configure(registration);}
}
// Filter实例对象注册
protected Dynamic addRegistration(String description, ServletContext servletContext) {Filter filter = this.getFilter();// 此处可将Filter实例添加到FilterDef =》filterDef.setFilter(filter)// 返回ApplicationFilterRegistration(filterDef, this.context)对象return servletContext.addFilter(this.getOrDeduceName(filter), filter);
}
// URL等匹配元数据注册
protected void configure(Dynamic registration) {super.configure(registration);EnumSet<DispatcherType> dispatcherTypes = this.dispatcherTypes;..........省略..........// 重点registration.addMappingForUrlPatterns(dispatcherTypes, this.matchAfter, StringUtils.toStringArray(this.urlPatterns));
}public void addMappingForUrlPatterns(EnumSet<DispatcherType> dispatcherTypes, boolean isMatchAfter, String... urlPatterns) {FilterMap filterMap = new FilterMap();filterMap.setFilterName(this.filterDef.getFilterName());..........if (urlPatterns != null) {for(int var7 = 0; var7 < urlPatterns.length; ++var7) {String urlPattern = urlPatterns[var7];filterMap.addURLPattern(urlPattern);}if (isMatchAfter) {// 此处即为添加匹配元数据到Servlet上下文中this.context.addFilterMap(filterMap);} else {this.context.addFilterMapBefore(filterMap);}}
}

二、ApplicationFilterFactory使用createFilterChain工厂方法创建ApplicationFilterChain链
createFilterChain有两大核心逻辑
1)创建ApplicationFilterChain实例

ApplicationFilterChain filterChain = null;
if (request instanceof Request) {Request req = (Request)request;if (Globals.IS_SECURITY_ENABLED) {filterChain = new ApplicationFilterChain();} else {filterChain = (ApplicationFilterChain)req.getFilterChain();if (filterChain == null) {// 核心逻辑,直接创建Chain实例,且构造器无其他初始化逻辑filterChain = new ApplicationFilterChain();// chain对象复用,注意这里req对象是org.apache.catalina.connector.Request// chain内容不复用,filterChain使用完毕会调用release方法释放资源req.setFilterChain(filterChain);}}
} else {filterChain = new ApplicationFilterChain();
}

2)过滤器链初始化【极简版】

// Servlet设置
filterChain.setServlet(servlet); // DispatcherServlet实例
StandardContext context = (StandardContext)wrapper.getParent(); // TomcatEmbeddedContext
// 获取Servlet上下文中的过滤器匹配元数据
FilterMap[] filterMaps = context.findFilterMaps();
if (filterMaps != null && filterMaps.length != 0) {// 分发类型,一般为RequestDispatcherType dispatcher = (DispatcherType)request.getAttribute("org.apache.catalina.core.DISPATCHER_TYPE");// 请求URI解析,此处忽略   String requestPath = xxx;String servletName = wrapper.getName(); // 值为dispatcherServletFilterMap filterMap;ApplicationFilterConfig filterConfig;for(int index = 0; index < filterMaps.length; ++index) {filterMap = filterMaps[index];// 目前Springboot项目基本只需解析matchFiltersURL方法,根据URL匹配对应Filterif (matchDispatcher(filterMap, dispatcher) && matchFiltersURL(filterMap, requestPath)) {filterConfig = (ApplicationFilterConfig)context.findFilterConfig(filterMap.getFilterName());if (filterConfig != null) {// 过滤器链中数组对象存的是ApplicationFilterConfig实例,而不是Filter实例,因为部分场景需要元数据作为判断条件filterChain.addFilter(filterConfig);}}}// Servlet匹配Filter当前无用,仅作参考。结构类似,代码忽略..............................return filterChain;
}

三、过滤器链执行入口:StandardWrapperValve
在StandardWrapperValve中,由invoke(Request request, Response response)方法内执行过滤器链,StandardWrapperValve前也是通过责任链模式一步步传递过来,也有相似的Valve实例。

过滤器链执行流程很简单,可以简化为以下过程:
// 注:这里传给Filter的其实是RequestFacade对象,包装了底层的Request对象,Response同理
1、filterChain.doFilter(request.getRequest(), response.getResponse())

2、中间过滤器链执行流程,已在其他博客说明

//过滤器链每次执行后,释放资源
3、filterChain.release()

总结:本文将Filter在Servlet上下文的注册流程、FilterChain过滤器链的封装流程基本讲述完成,其他Filter相关知识可参考之前其他博客内容,剩余细节不在展开。

思考:
1、过滤器池化相关概念,实际不是FilterChain的池化,其每次会recycle,而是org.apache.coyote.Request请求对象的池化(注意:此对象不是实现HttpServletRequest的org.apache.catalina.connector.Request)。Request对象较为底层且复杂,在并发量较低时,同一接口间隔请求都是一个Request对象,使用完成也会调用recycle回收,response同理。
2、FilterChain在Request池化基础上,每次不会新建,但是每次请求都会重新生成ApplicationFilterConfig数组。按现在Springboot请求流程,暂不清楚为啥需要recycle,(只是元数据封装,性能影响很小)可能考虑到Filter可能在服务期间被destroy?
3、至于线程安全问题,FilterChain是多例的,Filter是单例的,但是被多个FilterChain封装,也能并发执行,所以不要在Filter中定义共享变量。

相关文章:

【记录版】SpringBoot下Filter注册源码解读

SpringBoot TomcatEmbeddedContext Servlet ApplicationFilterChain Filter 背景&#xff1a; 在之前博客中有说明SpringBoot内嵌Web容器后&#xff0c;Filter及Servlet解析与注册流程的变化。将Filter实例封装成FilterRegistrationBean实例并添加到ServletContext后&…...

WPF的WebBrowser控件

在 WPF 中显示网页&#xff0c;你可以使用 WebBrowser 控件来实现。WebBrowser 控件是一个嵌入式的浏览器控件&#xff0c;可以加载和显示网页内容。 以下是在 WPF 中显示网页的示例代码&#xff1a; <Window x:Class"WpfApp.MainWindow"xmlns"http://sche…...

WX小程序案例(一):弹幕列表

WXML内容 <!--pages/formCase/formCase.wxml--> <!-- <text>pages/formCase/formCase.wxml</text> --> <view class"bk bkimg"><!-- <image src"/static/imgs/ceeb653ely1g9na2k0k6ug206o06oaa8.gif" mode"scal…...

基于ssm医用物理学实验考核系统论文

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本医用物理学实验考核系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数…...

鸿蒙HarmonyOS4.0 入门与实战

一、开发准备: 熟悉鸿蒙官网安装DevEco Studio熟悉鸿蒙官网 HarmonyOS应用开发官网 - 华为HarmonyOS打造全场景新服务 应用设计相关资源: 开发相关资源: 例如开发工具 DevEco Studio 的下载 应用发布: 开发文档:...

论文阅读——GroupViT

GroupViT: Semantic Segmentation Emerges from Text Supervision 一、思想 把Transformer层分为多个组阶段grouping stages&#xff0c;每个stage通过自注意力机制学习一组tokens&#xff0c;然后使用学习到的组tokens通过分组模块Grouping Block融合相似的图片tokens。通过这…...

时光机器:用rrweb打造可回溯的用户体验!

在现代Web应用中&#xff0c;理解用户如何与你的产品互动变得越来越重要。rrweb&#xff08;record and replay the web&#xff09;是一个开源库&#xff0c;它能够记录用户在网站上的所有操作&#xff0c;并能够像回放视频一样回放这些操作。这就像给你的网站装上了一台时光机…...

不同的葡萄品种的葡萄酒有什么共同特质?

在某种程度上几乎所有的葡萄酒都是混合的&#xff0c;在大多数葡萄酒产地&#xff0c;法律允许在单一品种葡萄酒中混入高达15%的另一种葡萄酒&#xff0c;且还能被称为由主要葡萄酿造的单一品种葡萄酒酒。这些单一品种葡萄酒混合了少量其他葡萄酒&#xff0c;是为了创造一个特质…...

Visual Studio编辑器中C4996 ‘scanf‘: This function or variable may be unsafe.问题解决方案

目录 ​编辑 题目&#xff1a;简单的ab 1. 题目描述 2. 输入格式 3. 输出格式 4. 样例输入 5. 样例输出 6. 解题思路 7. 代码示例 8. 报错解决 方案一 方案二 方案三 方案四 总结 题目&#xff1a;简单的ab 1. 题目描述 输入两个整数a和b&#xff0c;…...

C与C++编程语言的区别和联系

一、引言 C和C是两种广泛使用的编程语言&#xff0c;它们都在软件开发领域有着广泛的应用。虽然C是从C语言演化而来的&#xff0c;但两者之间存在一些重要的区别和联系。本文将详细介绍这两种编程语言的相同点和不同点&#xff0c;并通过实际例子进行说明。 二、C与C的相同点 …...

UE4 UMG 颜色字体和PS对应关系

与PS中对应的是Hex sRGB色号 但是PS中采用的16进制色号为6位 UE4中的为8位 UMG制作时默认dpi为96像素/英寸&#xff0c;psd默认dpi是72像素/英寸。 在GUI设计时将dpi设为96&#xff0c;或者将72dpi下字体的字号乘以0.75&#xff0c;都能还原效果图中的效果。...

EasyExcel处理表头的缓存设置

在学习EasyExcel 时会发现针对使用类模型配置表头相关属性时&#xff0c;EasyExcel 会使用到缓存技术以提升表头的解析速度如下代码&#xff1a; 这些参数再何时设置的哪&#xff1f; 在easyExcel 基础参数设置中会有这个参数filedCacheLocation 。默认采用的使用线程级别的…...

数据挖掘任务一般流程

数据挖掘是从大量数据中提取有价值信息的过程。它涉及多个步骤&#xff0c;每一步都对整个数据挖掘过程至关重要。以下是数据挖掘任务的一般流程&#xff1a; 业务理解&#xff1a; 确定业务目标。评估当前情况。定义数据挖掘问题。制定一个初步计划来达到这些目标。 数据理…...

人工智能计算机视觉:解析现状与未来趋势

导言 随着人工智能的迅速发展&#xff0c;计算机视觉技术逐渐成为引领创新的关键领域。本文将深入探讨人工智能在计算机视觉方面的最新进展、关键挑战以及未来可能的趋势。 1. 简介 计算机视觉是人工智能的一个重要分支&#xff0c;其目标是使机器具备类似于人类视觉的能力。这…...

5.1 C++11强类型枚举

一、C枚举的缺陷 1.类型冲突 枚举值和类型都是全局可见的&#xff0c; 与正常C的namespace、类等都是格格不入的&#xff0c;并且还容易导致冲突。 enum Type { General, Light, Medium, Heavy }; enum Category { General, Pistol, MachineGun, Cannon }; 如果在相同作用域…...

Android : BottomNavigation底部导航_简单应用

示例图&#xff1a; 1.先创建底部导航需要的图片 res → New → Vector Asset 创建三个矢量图 图片1 baseline_home.xml <vector android:height"24dp" android:tint"#000000"android:viewportHeight"24" android:viewportWidth"24…...

基于ssm培训学校教学管理平台论文

摘 要 社会的进步&#xff0c;教育行业发展迅速&#xff0c;人们对教育越来越重视&#xff0c;在当今网络普及的情况下&#xff0c;教学管理模式也开始逐渐网络化&#xff0c;学校开始网络教学管理模式。 本文研究的培训学校教学管理平台基于SSM框架&#xff0c;采用Java技术和…...

关于嵌入式开发的一些信息汇总:C标准、芯片架构、编译器、MISRA-C

关于嵌入式开发的一些信息汇总&#xff1a;C标准、芯片架构、编译器、MISRA-C 关于C标准芯片架构是什么&#xff1f;架构对芯片有什么作用&#xff1f;arm架构X86架构mips架构小结 编译器LLVM是什么&#xff1f;前端在干什么&#xff1f;后端在干什么&#xff1f; MISRA C的诞生…...

java实现局域网内视频投屏播放(二)爬虫

代码链接 视频播放原理 大多视频网站使用的是m3u8&#xff0c;m3u8其实不是一个真正的视频文件&#xff0c;而是一个视频播放列表&#xff08;playlist&#xff09;。它是一种文本文件&#xff0c;里面记录了一系列的视频片段&#xff08;segment&#xff09;的网络地址。这些…...

a标签的target属性

<a> 标签的 target 属性规定在何处打开链接文档。 最常用的两个值是&#xff1a; _self &#xff1a; 在当前窗口打开被链接文档 _blank&#xff1a;在新窗口打开被链接文档 就是常见浏览网页打开链接的方式...

【杂谈】-递归进化:人工智能的自我改进与监管挑战

递归进化&#xff1a;人工智能的自我改进与监管挑战 文章目录 递归进化&#xff1a;人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管&#xff1f;3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...

docker 部署发现spring.profiles.active 问题

报错&#xff1a; org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...

Linux离线(zip方式)安装docker

目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1&#xff1a;修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本&#xff1a;CentOS 7 64位 内核版本&#xff1a;3.10.0 相关命令&#xff1a; uname -rcat /etc/os-rele…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)

本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.

ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #&#xff1a…...

逻辑回归暴力训练预测金融欺诈

简述 「使用逻辑回归暴力预测金融欺诈&#xff0c;并不断增加特征维度持续测试」的做法&#xff0c;体现了一种逐步建模与迭代验证的实验思路&#xff0c;在金融欺诈检测中非常有价值&#xff0c;本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...

毫米波雷达基础理论(3D+4D)

3D、4D毫米波雷达基础知识及厂商选型 PreView : https://mp.weixin.qq.com/s/bQkju4r6med7I3TBGJI_bQ 1. FMCW毫米波雷达基础知识 主要参考博文&#xff1a; 一文入门汽车毫米波雷达基本原理 &#xff1a;https://mp.weixin.qq.com/s/_EN7A5lKcz2Eh8dLnjE19w 毫米波雷达基础…...

解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用

在工业制造领域&#xff0c;无损检测&#xff08;NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统&#xff0c;以非接触式光学麦克风技术为核心&#xff0c;打破传统检测瓶颈&#xff0c;为半导体、航空航天、汽车制造等行业提供了高灵敏…...

LangFlow技术架构分析

&#x1f527; LangFlow 的可视化技术栈 前端节点编辑器 底层框架&#xff1a;基于 &#xff08;一个现代化的 React 节点绘图库&#xff09; 功能&#xff1a; 拖拽式构建 LangGraph 状态机 实时连线定义节点依赖关系 可视化调试循环和分支逻辑 与 LangGraph 的深…...

五子棋测试用例

一.项目背景 1.1 项目简介 传统棋类文化的推广 五子棋是一种古老的棋类游戏&#xff0c;有着深厚的文化底蕴。通过将五子棋制作成网页游戏&#xff0c;可以让更多的人了解和接触到这一传统棋类文化。无论是国内还是国外的玩家&#xff0c;都可以通过网页五子棋感受到东方棋类…...