SpringMVC源码-AbstractUrlHandlerMapping处理器映射器将实现Controller接口的方式定义的路径存储进去
DispatcherServlet的initStrategies方法用来初始化SpringMVC的九大内置组件
initStrategies
protected void initStrategies(ApplicationContext context) {// 初始化 MultipartResolver:主要用来处理文件上传.如果定义过当前类型的bean对象,那么直接获取,如果没有的话,可以为nullinitMultipartResolver(context);// 初始化 LocaleResolver:主要用来处理国际化配置,基于URL参数的配置(AcceptHeaderLocaleResolver),基于session的配置(SessionLocaleResolver),基于cookie的配置(CookieLocaleResolver)initLocaleResolver(context);// 初始化 ThemeResolver:主要用来设置主题ThemeinitThemeResolver(context);// 初始化 HandlerMapping:映射器,用来将对应的request跟controller进行对应initHandlerMappings(context);// 初始化 HandlerAdapter:处理适配器,主要包含Http请求处理器适配器,简单控制器处理器适配器,注解方法处理器适配器initHandlerAdapters(context);// 初始化 HandlerExceptionResolver:基于HandlerExceptionResolver接口的异常处理initHandlerExceptionResolvers(context);// 初始化 RequestToViewNameTranslator:当controller处理器方法没有返回一个View对象或逻辑视图名称,并且在该方法中没有直接往response的输出流里面写数据的时候,spring将会采用约定好的方式提供一个逻辑视图名称initRequestToViewNameTranslator(context);// 初始化 ViewResolver: 将ModelAndView选择合适的视图进行渲染的处理器initViewResolvers(context);// 初始化 FlashMapManager: 提供请求存储属性,可供其他请求使用initFlashMapManager(context);}
initHandlerMappings初始化 HandlerMapping:映射器,用来将对应的request跟controller进行对应,该方法是在构造SpringMVC容器调用的。
调用链路如下:
ApplicationObjectSupport实现了ApplicationContextAware接口,所以会调用setApplicationContext:78, ApplicationObjectSupport (org.springframework.context.support)
invokeAwareInterfaces:146, ApplicationContextAwareProcessor (org.springframework.context.support)
postProcessBeforeInitialization:118, ApplicationContextAwareProcessor (org.springframework.context.support)
applyBeanPostProcessorsBeforeInitialization:497, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
完成实例化、属性填充之后进行初始化调用bpp的方法——initializeBean:2256, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
doCreateBean:736, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
createBean:630, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
createBean:361, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
createDefaultStrategy:957, DispatcherServlet (org.springframework.web.servlet)
获得默认配置的handlerMapping类——getDefaultStrategies:925, DispatcherServlet (org.springframework.web.servlet)
initHandlerMappings:657, DispatcherServlet (org.springframework.web.servlet)
initStrategies:529, DispatcherServlet (org.springframework.web.servlet)
onRefresh:514, DispatcherServlet (org.springframework.web.servlet)
onApplicationEvent:901, FrameworkServlet (org.springframework.web.servlet)
onApplicationEvent:1277, FrameworkServlet$ContextRefreshListener (org.springframework.web.servlet)
onApplicationEvent:1273, FrameworkServlet$ContextRefreshListener (org.springframework.web.servlet)
onApplicationEvent:64, GenericApplicationListenerAdapter (org.springframework.context.event)
onApplicationEventInternal:109, SourceFilteringListener (org.springframework.context.event)
onApplicationEvent:73, SourceFilteringListener (org.springframework.context.event)
doInvokeListener:215, SimpleApplicationEventMulticaster (org.springframework.context.event)
invokeListener:202, SimpleApplicationEventMulticaster (org.springframework.context.event)
multicastEvent:164, SimpleApplicationEventMulticaster (org.springframework.context.event)
publishEvent:440, AbstractApplicationContext (org.springframework.context.support)
publishEvent:379, AbstractApplicationContext (org.springframework.context.support)
finishRefresh:1053, AbstractApplicationContext (org.springframework.context.support)
refresh:618, AbstractApplicationContext (org.springframework.context.support)
configureAndRefreshWebApplicationContext:759, FrameworkServlet (org.springframework.web.servlet)
createWebApplicationContext:715, FrameworkServlet (org.springframework.web.servlet)
createWebApplicationContext:773, FrameworkServlet (org.springframework.web.servlet)
initWebApplicationContext:625, FrameworkServlet (org.springframework.web.servlet)
initServletBean:536, FrameworkServlet (org.springframework.web.servlet)
init:185, HttpServletBean (org.springframework.web.servlet)
init:158, GenericServlet (javax.servlet)
initServlet:1164, StandardWrapper (org.apache.catalina.core)
loadServlet:1117, StandardWrapper (org.apache.catalina.core)
load:1010, StandardWrapper (org.apache.catalina.core)
loadOnStartup:4957, StandardContext (org.apache.catalina.core)
startInternal:5264, StandardContext (org.apache.catalina.core)
start:183, LifecycleBase (org.apache.catalina.util)
addChildInternal:726, ContainerBase (org.apache.catalina.core)
addChild:698, ContainerBase (org.apache.catalina.core)
addChild:696, StandardHost (org.apache.catalina.core)
manageApp:1783, HostConfig (org.apache.catalina.startup)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invoke:293, BaseModelMBean (org.apache.tomcat.util.modeler)
invoke:819, DefaultMBeanServerInterceptor (com.sun.jmx.interceptor)
invoke:801, JmxMBeanServer (com.sun.jmx.mbeanserver)
createStandardContext:460, MBeanFactory (org.apache.catalina.mbeans)
createStandardContext:408, MBeanFactory (org.apache.catalina.mbeans)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invoke:293, BaseModelMBean (org.apache.tomcat.util.modeler)
invoke:819, DefaultMBeanServerInterceptor (com.sun.jmx.interceptor)
invoke:801, JmxMBeanServer (com.sun.jmx.mbeanserver)
invoke:468, MBeanServerAccessController (com.sun.jmx.remote.security)
doOperation:1468, RMIConnectionImpl (javax.management.remote.rmi)
access$300:76, RMIConnectionImpl (javax.management.remote.rmi)
run:1309, RMIConnectionImpl$PrivilegedOperation (javax.management.remote.rmi)
doPrivileged:-1, AccessController (java.security)
doPrivilegedOperation:1408, RMIConnectionImpl (javax.management.remote.rmi)
invoke:829, RMIConnectionImpl (javax.management.remote.rmi)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
dispatch:346, UnicastServerRef (sun.rmi.server)
run:200, Transport$1 (sun.rmi.transport)
run:197, Transport$1 (sun.rmi.transport)
doPrivileged:-1, AccessController (java.security)
serviceCall:196, Transport (sun.rmi.transport)
handleMessages:568, TCPTransport (sun.rmi.transport.tcp)
run0:826, TCPTransport$ConnectionHandler (sun.rmi.transport.tcp)
lambda$run$0:683, TCPTransport$ConnectionHandler (sun.rmi.transport.tcp)
run:-1, 1637217430 (sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$$Lambda$26)
doPrivileged:-1, AccessController (java.security)
run:682, TCPTransport$ConnectionHandler (sun.rmi.transport.tcp)
runWorker:1142, ThreadPoolExecutor (java.util.concurrent)
run:617, ThreadPoolExecutor$Worker (java.util.concurrent)
run:748, Thread (java.lang)
ApplicationObjectSupport等相关类继承关系

ApplicationObjectSupport实现了ApplicationContextAware接口,setApplicationContext方法里调用initApplicationContext(context);

经这一步一直调用到:
AbstractHandlerMapping的initApplicationContext方法:
/**初始化拦截器* Initializes the interceptors.* @see #extendInterceptors(java.util.List)* @see #initInterceptors()*/@Overrideprotected void initApplicationContext() throws BeansException {// 空实现,交给子类实现,用于注册自定义的拦截器到interceptors中,目前暂无子类实现extendInterceptors(this.interceptors);// 扫描已注册的MappedInterceptor的Bean们,添加到adaptedInterceptors中detectMappedInterceptors(this.adaptedInterceptors);// 将interceptors初始化成 HandlerInterceptor类型,添加到adaptedInterceptors中initInterceptors();}
detectMappedInterceptors执行:

SpringMVC的配置文件applicationContext.xml有定义拦截器:
<mvc:interceptors><bean class="com.mashibing.interceptor.HandlerMappingInterceptor"/></mvc:interceptors>
将配置文件中配置的拦截器生成放在mappedInterceptors中。
initInterceptors执行,interceptors为空,跳过执行。
/*** 初始化interceptors,并适配HandlerInterceptors和WebRequestInterceptor** Initialize the specified interceptors adapting* {@link WebRequestInterceptor}s to {@link HandlerInterceptor}.* @see #setInterceptors* @see #adaptInterceptor*/protected void initInterceptors() {if (!this.interceptors.isEmpty()) {for (int i = 0; i < this.interceptors.size(); i++) {Object interceptor = this.interceptors.get(i);if (interceptor == null) {throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null");}// 将interceptors初始化成HandlerInterceptor类型,添加到adaptedInterceptors中// 注意,HandlerInterceptor无需进行路径匹配,直接拦截全部this.adaptedInterceptors.add(adaptInterceptor(interceptor));}}}
AbstractDetectingUrlHandlerMapping的initApplicationContext中方法detectHandlers开始执行:
AbstractDetectingUrlHandlerMapping类的detectHandlers方法开始执行:
/*** 根据配置的detectHandlersInAncestorContexts参数从springmvc容器或者父容器中找到所有bean的beanName,然后使用determineUrlsForHandler方法* 对每个beanName解析出对应的urls,如果解析结果不为空,则解析出urls和beanName注册到父类的map中,** Register all handlers found in the current ApplicationContext.* <p>The actual URL determination for a handler is up to the concrete* {@link #determineUrlsForHandler(String)} implementation. A bean for* which no such URLs could be determined is simply not considered a handler.* @throws org.springframework.beans.BeansException if the handler couldn't be registered* @see #determineUrlsForHandler(String)*/protected void detectHandlers() throws BeansException {// 从spring上下文获取所有Object类型的bean名称ApplicationContext applicationContext = obtainApplicationContext();//获取的是springmvc的容器// 获取容器中所有bean的名字String[] beanNames = (this.detectHandlersInAncestorContexts ?BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class) :applicationContext.getBeanNamesForType(Object.class));// Take any bean name that we can determine URLs for.// 对每一个beanName解析url,如果能解析到就注册到父类的map中for (String beanName : beanNames) {// 使用beanName解析url,模板方法,有子类实现 检查给定bean的名称和别名,查找以“”开头的url。String[] urls = determineUrlsForHandler(beanName);// 如果该bean存在对应的url,则添加该处理器if (!ObjectUtils.isEmpty(urls)) {// URL paths found: Let's consider it a handler.// 调用父类的方法,往handlerMap中添加注册器registerHandler(urls, beanName);}}if ((logger.isDebugEnabled() && !getHandlerMap().isEmpty()) || logger.isTraceEnabled()) {logger.debug("Detected " + getHandlerMap().size() + " mappings in " + formatMappingName());}}
beanNames 是SpringMVC容器的所有对象的名称:使用beanName解析url,模板方法,有子类实现 检查给定bean的名称和别名,查找以“/”开头的url。调用父类的方法,往handlerMap中添加注册器
applicationContext.xml文件定义的bean是以/开头的,会被放到handlerMap
<bean name="/test01" class="com.mashibing.controller.testController.Test01"></bean><bean id="/test02" class="com.mashibing.controller.testController.Test02"></bean>


最终放到AbstractUrlHandlerMapping的handlerMap中
相关文章:
SpringMVC源码-AbstractUrlHandlerMapping处理器映射器将实现Controller接口的方式定义的路径存储进去
DispatcherServlet的initStrategies方法用来初始化SpringMVC的九大内置组件 initStrategies protected void initStrategies(ApplicationContext context) {// 初始化 MultipartResolver:主要用来处理文件上传.如果定义过当前类型的bean对象,那么直接获取࿰…...
满填充透明背景二维码生成
前几天项目上线的时候发现一个问题:通过Hutool工具包生成的二维码在内容较少时无法填满(Margin 已设置为 0)给定大小的图片。因此导致前端在显示二维码时样式异常。 从图片中我们可以看到,相同大小的图片,留白内容是不一样的。其中上半部分…...
Python | Leetcode Python题解之第452题用最少数量的箭引爆气球
题目: 题解: class Solution:def findMinArrowShots(self, points: List[List[int]]) -> int:if not points:return 0points.sort(keylambda balloon: balloon[1])pos points[0][1]ans 1for balloon in points:if balloon[0] > pos:pos balloo…...
代码随想录 | Day26 | 二叉树:二叉搜索树中的插入操作删除二叉搜索树中的节点修剪二叉搜索树
代码随想录 | Day26 | 二叉树:二叉搜索树中的插入操作&&删除二叉搜索树中的节点&&修剪二叉搜索树 主要学习内容: 二叉搜索树的插入删除操作 701.二叉搜索树中的插入操作 701. 二叉搜索树中的插入操作 - 力扣(LeetCode&…...
使用Apifox创建接口文档,部署第一个简单的基于Vue+Axios的前端项目
前言 在当今软件开发的过程中,接口文档的创建至关重要,它不仅能够帮助开发人员更好地理解系统架构,还能确保前后端开发的有效协同。Apifox作为一款集API文档管理、接口调试、Mock数据模拟为一体的工具,能够大幅度提高开发效率。在…...
TCP的第三次握手没有回复,会出现哪些问题现象
从三次握手的一开始来讲,刚开始客户端和服务器都处于close状态 这里不能是2次握手的原因就在于,服务器端即女孩子,无法确认客户端即男孩子,是否已经收到了,我也愿意建立连接即我也爱你,这一条最终确认的信息…...
【工具】arxiv_latex_cleaner 去除latex注释
https://github.com/google-research/arxiv-latex-cleaner/issues/24 文章目录 1.修改编码2.如何安装2.1.打包2.2.安装 3.测试功能 注意:需要创建python3.9的环境 1.修改编码 官方提供的arxiv_latex_cleaner的编码格式是有问题的,见这里。这个有位朋友说…...
macOS开发环境配置与应用开发
一、macOS开发环境配置 1. 安装Xcode Xcode 是Apple官方开发环境工具,用于macOS、iOS、watchOS和tvOS应用开发。它集成了代码编辑、编译、调试、性能分析、界面设计等功能。 下载与安装: 打开 App Store,搜索“Xcode”。 点击安装ÿ…...
15分钟学 Python :编程工具 Idea 和 vscode 中配置 Python ( 补充 )
编程工具配置 Python 在 IDE 和 VSCode 中 在编程学习的过程中,选择合适的开发工具至关重要。本文将详细介绍在两种流行的IDE(IntelliJ IDEA 和 Visual Studio Code)中如何配置Python环境,帮助你更高效地进行Python开发。 一、编…...
MyBatis 如何实现延迟加载?深度探讨 MyBatis 的延迟加载:如何优化数据访问效率
在当今的应用程序开发中,尤其是与数据库交互时,性能成为了重中之重。频繁的数据库访问会导致响应时间变慢,甚至影响用户体验。为了优化数据访问,MyBatis 提供了延迟加载(Lazy Loading)的强大功能。本文将详…...
springboot系列--web相关知识探索三
一、前言 web相关知识探索二中研究了请求是如何映射到具体接口(方法)中的,本次文章主要研究请求中所带的参数是如何映射到接口参数中的,也即请求参数如何与接口参数绑定。主要有四种、分别是注解方式、Servlet API方式、复杂参数、…...
AI冲击下的编程职业未来:你缺的不是技术,而是跨学科思维!
随着AIGC技术(如ChatGPT、MidJourney、Claude等大语言模型)的不断进化,AI辅助编程工具迅速普及,程序员的工作方式正在经历前所未有的转型。代码自动补全、智能化代码生成等功能大幅提升了工作效率,但与此同时ÿ…...
是否是 2 的幂次方
给你一个整数 n,请你判断该整数是否是 2 的幂次方。如果是,返回 true ;否则,返回 false 。 如果存在一个整数 x 使得 n 2x ,则认为 n 是 2 的幂次方。 示例 1: 输入:n 1 输出:tr…...
音视频入门
一个视频,一秒内普遍大于等于25帧。 入门知识: 1.帧,一张画面就是一帧。一个视频就是由许许多多帧组成的。 帧率,单位时间内帧的数量。单位:帧/秒 或 fps。 分类:I帧,P帧,B帧 I…...
C++随心记 续一
C中的模板 在其它语言中如Java或者C#中可能叫做泛型,在C中为模板,泛型的限制通常比模板多。模板可以解决多次的代码重复问题,如以下场景 #include <iostream> #include <string>void print(int value) {std::cout << val…...
消息中间件:RabbitMQ
消息中间件:RabbitMQ 前言安装Window安装Linux安装 管理页面什么是RabbitMQ?入门基本概念简单队列工作队列(Work Queues)发布/订阅(Publish/Subscribe)临时队列 路由(Routing)主题&a…...
sql-labs:42~65
less42(单引号闭合、报错回显) login_useradmin login_password123 and if(11,sleep(2),1) # # 单引号闭合 login_useradmin login_password123and updatexml(1,concat(0x7e,database(),0x7e),1)# # 报错回显…...
KaTeX.js渲染数学公式
什么是KaTeX.js ? KaTeX 是一个集成速度快且功能丰富的数学公式渲染库,专为 Web 设计。它由 Khan Academy 开发,提供接近印刷品质的数学公式展示,同时保持与浏览器的高效互动性。KaTeX 特点包括快速渲染速度、高质量的输出、独立运行、跨平…...
算法训练营打卡Day19
目录 1.二叉搜索树的最近公共祖先 2.二叉树中的插入操作 3.删除二叉搜索树中的节点 题目1、二叉搜索树的最近公共祖先 力扣题目链接(opens new window) 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为:“对于有…...
H.264编解码工具 - FFmpeg
一、简介 FFmpeg是一款用于处理多媒体数据的开源软件,可以完成音频、视频和多媒体流的编解码、转码、解码、录制、流媒体播放等功能。它提供了丰富的命令行工具和库函数,适用于各种平台和操作系统。 FFmpeg支持多种常见的音视频格式,包括MP3、WAV、FLAC、MP4、AVI、MKV等。它…...
KubeSphere 容器平台高可用:环境搭建与可视化操作指南
Linux_k8s篇 欢迎来到Linux的世界,看笔记好好学多敲多打,每个人都是大神! 题目:KubeSphere 容器平台高可用:环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
HBuilderX安装(uni-app和小程序开发)
下载HBuilderX 访问官方网站:https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本: Windows版(推荐下载标准版) Windows系统安装步骤 运行安装程序: 双击下载的.exe安装文件 如果出现安全提示&…...
【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...
NLP学习路线图(二十三):长短期记忆网络(LSTM)
在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...
OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...
人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式
今天是关于AI如何在教学中增强学生的学习体验,我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育,这并非炒作,而是已经发生的巨大变革。教育机构和教育者不能忽视它,试图简单地禁止学生使…...
腾讯云V3签名
想要接入腾讯云的Api,必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口,但总是卡在签名这一步,最后放弃选择SDK,这次终于自己代码实现。 可能腾讯云翻新了接口文档,现在阅读起来,清晰了很多&…...
毫米波雷达基础理论(3D+4D)
3D、4D毫米波雷达基础知识及厂商选型 PreView : https://mp.weixin.qq.com/s/bQkju4r6med7I3TBGJI_bQ 1. FMCW毫米波雷达基础知识 主要参考博文: 一文入门汽车毫米波雷达基本原理 :https://mp.weixin.qq.com/s/_EN7A5lKcz2Eh8dLnjE19w 毫米波雷达基础…...
