【记录版】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 背景: 在之前博客中有说明SpringBoot内嵌Web容器后,Filter及Servlet解析与注册流程的变化。将Filter实例封装成FilterRegistrationBean实例并添加到ServletContext后&…...
WPF的WebBrowser控件
在 WPF 中显示网页,你可以使用 WebBrowser 控件来实现。WebBrowser 控件是一个嵌入式的浏览器控件,可以加载和显示网页内容。 以下是在 WPF 中显示网页的示例代码: <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医用物理学实验考核系统论文
摘 要 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本医用物理学实验考核系统就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数…...
鸿蒙HarmonyOS4.0 入门与实战
一、开发准备: 熟悉鸿蒙官网安装DevEco Studio熟悉鸿蒙官网 HarmonyOS应用开发官网 - 华为HarmonyOS打造全场景新服务 应用设计相关资源: 开发相关资源: 例如开发工具 DevEco Studio 的下载 应用发布: 开发文档:...
论文阅读——GroupViT
GroupViT: Semantic Segmentation Emerges from Text Supervision 一、思想 把Transformer层分为多个组阶段grouping stages,每个stage通过自注意力机制学习一组tokens,然后使用学习到的组tokens通过分组模块Grouping Block融合相似的图片tokens。通过这…...
时光机器:用rrweb打造可回溯的用户体验!
在现代Web应用中,理解用户如何与你的产品互动变得越来越重要。rrweb(record and replay the web)是一个开源库,它能够记录用户在网站上的所有操作,并能够像回放视频一样回放这些操作。这就像给你的网站装上了一台时光机…...
不同的葡萄品种的葡萄酒有什么共同特质?
在某种程度上几乎所有的葡萄酒都是混合的,在大多数葡萄酒产地,法律允许在单一品种葡萄酒中混入高达15%的另一种葡萄酒,且还能被称为由主要葡萄酿造的单一品种葡萄酒酒。这些单一品种葡萄酒混合了少量其他葡萄酒,是为了创造一个特质…...
Visual Studio编辑器中C4996 ‘scanf‘: This function or variable may be unsafe.问题解决方案
目录 编辑 题目:简单的ab 1. 题目描述 2. 输入格式 3. 输出格式 4. 样例输入 5. 样例输出 6. 解题思路 7. 代码示例 8. 报错解决 方案一 方案二 方案三 方案四 总结 题目:简单的ab 1. 题目描述 输入两个整数a和b,…...
C与C++编程语言的区别和联系
一、引言 C和C是两种广泛使用的编程语言,它们都在软件开发领域有着广泛的应用。虽然C是从C语言演化而来的,但两者之间存在一些重要的区别和联系。本文将详细介绍这两种编程语言的相同点和不同点,并通过实际例子进行说明。 二、C与C的相同点 …...
UE4 UMG 颜色字体和PS对应关系
与PS中对应的是Hex sRGB色号 但是PS中采用的16进制色号为6位 UE4中的为8位 UMG制作时默认dpi为96像素/英寸,psd默认dpi是72像素/英寸。 在GUI设计时将dpi设为96,或者将72dpi下字体的字号乘以0.75,都能还原效果图中的效果。...
EasyExcel处理表头的缓存设置
在学习EasyExcel 时会发现针对使用类模型配置表头相关属性时,EasyExcel 会使用到缓存技术以提升表头的解析速度如下代码: 这些参数再何时设置的哪? 在easyExcel 基础参数设置中会有这个参数filedCacheLocation 。默认采用的使用线程级别的…...
数据挖掘任务一般流程
数据挖掘是从大量数据中提取有价值信息的过程。它涉及多个步骤,每一步都对整个数据挖掘过程至关重要。以下是数据挖掘任务的一般流程: 业务理解: 确定业务目标。评估当前情况。定义数据挖掘问题。制定一个初步计划来达到这些目标。 数据理…...
人工智能计算机视觉:解析现状与未来趋势
导言 随着人工智能的迅速发展,计算机视觉技术逐渐成为引领创新的关键领域。本文将深入探讨人工智能在计算机视觉方面的最新进展、关键挑战以及未来可能的趋势。 1. 简介 计算机视觉是人工智能的一个重要分支,其目标是使机器具备类似于人类视觉的能力。这…...
5.1 C++11强类型枚举
一、C枚举的缺陷 1.类型冲突 枚举值和类型都是全局可见的, 与正常C的namespace、类等都是格格不入的,并且还容易导致冲突。 enum Type { General, Light, Medium, Heavy }; enum Category { General, Pistol, MachineGun, Cannon }; 如果在相同作用域…...
Android : BottomNavigation底部导航_简单应用
示例图: 1.先创建底部导航需要的图片 res → New → Vector Asset 创建三个矢量图 图片1 baseline_home.xml <vector android:height"24dp" android:tint"#000000"android:viewportHeight"24" android:viewportWidth"24…...
基于ssm培训学校教学管理平台论文
摘 要 社会的进步,教育行业发展迅速,人们对教育越来越重视,在当今网络普及的情况下,教学管理模式也开始逐渐网络化,学校开始网络教学管理模式。 本文研究的培训学校教学管理平台基于SSM框架,采用Java技术和…...
关于嵌入式开发的一些信息汇总:C标准、芯片架构、编译器、MISRA-C
关于嵌入式开发的一些信息汇总:C标准、芯片架构、编译器、MISRA-C 关于C标准芯片架构是什么?架构对芯片有什么作用?arm架构X86架构mips架构小结 编译器LLVM是什么?前端在干什么?后端在干什么? MISRA C的诞生…...
java实现局域网内视频投屏播放(二)爬虫
代码链接 视频播放原理 大多视频网站使用的是m3u8,m3u8其实不是一个真正的视频文件,而是一个视频播放列表(playlist)。它是一种文本文件,里面记录了一系列的视频片段(segment)的网络地址。这些…...
a标签的target属性
<a> 标签的 target 属性规定在何处打开链接文档。 最常用的两个值是: _self : 在当前窗口打开被链接文档 _blank:在新窗口打开被链接文档 就是常见浏览网页打开链接的方式...
无mac在线申请hbuilderx打包ios证书的方法
hbuilderx是一个跨平台的开发工具,可以开发android和ios的app应用。打包hbuilderx应用需要hbuilderx打包证书。但是很多使用hbuilderx开发的程序员,并没有mac电脑,而申请ios的证书,hbuilderx官网的教程却是需要mac电脑的ÿ…...
[css] flex wrap 九宫格布局
<div class"box"><ul class"box-inner"><li>九宫格1</li><li>九宫格2</li><li>九宫格3</li><li>九宫格4</li><li>九宫格5</li><li>九宫格6</li><li>九宫格7&l…...
云上丝绸之路| 云轴科技ZStack成功实践精选(西北)
古有“丝绸之路” 今有丝绸之路经济带 丝路焕发新生,数智助力经济 云轴科技ZStack用“云”护航千行百业 沿丝绸之路,领略西北数字化。 古丝绸之路起点-陕西 集历史与现代交融,不仅拥有悠久的历史文化积淀,而且现代化、数字化发…...
Java8 IfPresent 与 forEach 的组合操作
一、需求背景 Java8的Optional接口是我们经常使用的一个接口,尤其是对对象进行判空的时候,需要经常使用到IfPresent()。 但是,如果是对List进行判空、循环的话,就稍显繁杂了,因为几乎每次对List进行操作的时候&a…...
WebGL+Three.js入门与实战——给画布换颜色、绘制一个点、三维坐标系
个人简介 👀个人主页: 前端杂货铺 🙋♂️学习方向: 主攻前端方向,正逐渐往全干发展 📃个人状态: 研发工程师,现效力于中国工业软件事业 🚀人生格言: 积跬步…...
SystemServer 进程启动过程
首语 SystemServer进程主要用于启动系统服务,诸如AMS、WMS、PMS都是由它来创建的。在系统的名称为"system_server",Android核心服务都是它启动,它是非常重要。 Zygote处理SystemServer进程 在 Zygote启动过程 文章中分析我们知道…...
Java EE 多线程之 JUC
文章目录 1. Callable 接口2. ReentrantLock3. 信号量4. CountDownLatch JUC这里就是指(java.util.concurrent) concurrent 就是并发的意思 这个包里的内容,主要就是一些多线程相关的组件 1. Callable 接口 Callable 也是一种创建线程的方式…...
Unity光照模型实践
光照作为3D渲染中最重要的部分之一,如何去模拟真实环境的光照是重要的研究内容,但是现实环境光照过于复杂,有很多经典好用的光照模型去近似真实光照。 根据基础的Phong模型 最终某个点的结果为 环境光Ambient 漫反射光Diffuse 高光Specula…...
从0创建并部署一个网页到服务器
创建一个页面 1 下载node.js 下载VScode 2 在Windows下找一个路径新建一个文件夹 例如:D:\study_project\PersonalWeb 3 VSCodee中打开文件夹 4 Windows下 管理员身份打开命令提示符,执行npm install -g vue/cli 5 VSCode下打开终端,执…...
Ubuntu 22.04 安装 OCI CLI
Ubuntu 22.04 安装 OCI CLI 安装命令 安装命令 wget https://codeload.github.com/oracle/oci-cli/zip/master -O oci-cli.zip pip install oci-cli.zip完结!...
百度验证文件放在wordpress根目录/深圳seo优化排名优化
一、注解实现MyBatis配置java注解是在jdk1.5版本之后开始加入的,不得不说注解对于我们开发人员来说是个很方便的东西,实现起来也非常的简单,下边我们说一下在MyBatis中使用注解来替换Mapper配置文件。packagecom.lhf.dao;importcom.lhf.entit…...
wordpress能做什么/微信广告平台推广
1,软硬件准备 软件:推荐使用VMwear,我用的是VMwear 10 镜像:CentOS 7 ,如果没有镜像可以去官网下载:https://www.centos.org/download/ 选择一个节点下载CentOS 7: 2.虚拟机准备 1)打开VMwea,点击左上角文…...
php网站后台搭建/安卓优化大师官方下载
iPhone12 mini、iPhone12、iPhone12 Pro、iPhone12 Pro Max四款手机,屏幕尺寸分别为5.4英寸、6.1英寸、6.1英寸、6.7英寸。采用OLED屏幕,多年不变的刘海屏设计。综合各方面这次iPhone12将不会有高刷新率。 iphone手机爆降2500 这活动太给力了机会不容错过…...
wordpress seo 主题/企业营销策划是做什么的
前面给大家分享了pandas.merge用法详解,这节分享pandas数据合并处理的姊妹篇,pandas.concat用法详解,参考利用Python进行数据分析与pandas官网进行整理。 pandas.merge参数列表如下图,其中只有objs是必须得参数,另外常…...
网站视频插件/2023今日新闻头条
资源描述:习题答案及解析 第1章 1.1.1 1. 单项选择题 1)A2)C3)B4)A5)C6)A 2.多项选择题 1)AB2)AB3)ABCD4)ABD5)ABCD6)ABC 3.判断题 1)F2)F 1.1.2 1. 单项选择题 1)A2)B3)A4)C5)D6)D7)A8)A9)C 2. 多项选择题 1)ABCDE2)ABC3)ABCD4)AB5)ABCD6)ABCD 3. 判断题 1)F2)T3)F…...
宿州哪有做网站的/百度产品优化排名软件
当我尝试在由Servlet(java页面),JSP,bean(java页面)和HTML页面组成的Netbeans中运行我的Java EE程序时,我在输出中出现此错误:In-place deployment at C:\Users\Derek\Documents\NetBeansProjects\EJBProject\EJBProject-war\build\webInitializing...deploy?pathC…...