【老王读SpringMVC-3】根据 url 是如何找到 controller method 的?
前面分析了 request 与 handler method 映射关系的注册,现在再来分析一下 SpringMVC 是如何根据 request 来获取对应的 handler method 的?
可能有人会说,既然已经将 request 与 handler method 映射关系注册保存在了 AbstractHandlerMethodMapping.MappingRegistry#registry 中,那么根据 request 不就能直接从 registry 中获取到相应的 handler method 了吗?
如果我们定义的 Controller 中的 @RequestMapping 都是普通的字符的话,那确实是可以直接通过 registry 获取 handler method。
但是,@RequestMapping 还支持占位符、通配符等 url,例如:
@RequestMapping("/resources/ima?e.png") // 匹配路径段中的一个字符
@RequestMapping("/resources/*.png") // 匹配路径段中的零个或多个字符
@RequestMapping("/resources/**") // 匹配多个路径段
@RequestMapping("/projects/{project}/versions") // 匹配路径段并将其捕获为变量
@RequestMapping("/projects/{project:[a-z]+}/versions") // 使用正则表达式匹配并捕获变量
所以,查找 request 对应的 handler method 就不是那么简单的事情了。
如何通过 request 获取 handler?
通过对 DispatcherServlet 的分析,我们知道 SpringMVC 获取 handler 的方法如下:
org.springframework.web.servlet.DispatcherServlet#getHandler()
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {if (this.handlerMappings != null) {for (HandlerMapping mapping : this.handlerMappings) {HandlerExecutionChain handler = mapping.getHandler(request);if (handler != null) {return handler;}}}return null;
}
可以看出,SpringMVC 是通过 HandlerMapping#getHandler() 来获取 request 对应的 handler method 处理程序的,最终会拿到一个 HandlerExecutionChain。
HandlerExecutionChain中包含了 request 对应的 handler method 和 interceptors。
HandlerMapping 的类图如下:

HandlerMapping 的实现类中其中最常用的是 RequestMappingHandlerMapping,它是专门用来处理 @RequestMapping 定义的 request 请求映射的。
获取 HandlerExecutionChain 的过程
HandlerExecutionChain 的获取是在 AbstractHandlerMapping#getHandler() 中完成的。
主要分成了两步:
1、获取 request 对应的 handler 程序
2、将 handler 和 相应的 HandlerInterceptors 组装成 HandlerExecutionChain

获取 request 对应的 handler method 的过程
上一步获取 HandlerExecutionChain 时,会调用 AbstractHandlerMethodMapping#getHandlerInternal() 来获取 request 对应的 handler method。
最终它会调用到 AbstractHandlerMethodMapping#lookupHandlerMethod() 来获取。

可以看到,AbstractHandlerMethodMapping#lookupHandlerMethod 实现了 request 与 handler method 映射关系的查找:
1、首先,通过 directPath 直接获取映射的 handler method
2、如果通过 directPath 没有找到的话,就循环 registry 中所有的映射,查出映射关系
3、如果获取到的映射的 handler 个数 > 1 的话,就找出最合适的匹配
DirectPath: 非 patterns 的 path。
非 patterns 的 path 是指 path 的定义中没有 ?、*、{} 的 path
通过 lookupPath 获取 HandlerMethod
AbstractHandlerMethodMapping#lookupHandlerMethod() 在寻找 HandlerMethod 时,有两种逻辑:
- 1、直接通过 directPath 快速查找
- 2、循环所有的映射关系,查找 RequestCondition 条件匹配,获取最合适的匹配
直接通过 directPath 快速查找
directPath 是最快速的方式,直接从 map 中获取匹配结果。
directPath 是不包含占位符、模式匹配符的普通路径,所以这种普通路径是最直接,也是效率最高的。
循环所有的映射关系,通过 RequestCondition 条件匹配,获取最合适的匹配
如果通过 directPath 没有找到任何匹配的话,就需要遍历所有注册的映射关系,找出最合适的匹配。
addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);// 这里会循环所有注册的映射关系,将满足 RequestCondition 的映射查找出来,存放到 matches 中
private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {for (T mapping : mappings) {T match = getMatchingMapping(mapping, request);if (match != null) {matches.add(new Match(match, this.mappingRegistry.getRegistrations().get(mapping)));}}
}
对于 @RequestMapping 注解形式的 url 映射,AbstractHandlerMethodMapping#getMatchingMapping() 最终会调用实现类的方法 RequestMappingInfoHandlerMapping#getMatchingCondition() 来获取匹配。

可以看到,Spring 会检查 RequestMappingInfo 是否满足以下 8 个条件:
1、请求方法 RequestMethod 是否匹配,如:GET, POST, PUT, DELETE 等
2、请求参数 params 是否匹配
3、请求头 header 是否匹配
4、consumes Content-Type 是否匹配
5、produces Content-Type 是否匹配
6、处理 directPath 和 通配符的请求映射匹配
7、处理 ant 风格的请求映射匹配
8、处理自定义的请求映射条件匹配
关于 RequestCondition 的详细分析查看 @RequstMapping和RequestCondition
小结
SpringMVC 是通过 HandlerMapping#getHandler() 来获取 request 对应的 handler method 处理程序的。
底层实现是通过 AbstractHandlerMethodMapping#lookupHandlerMethod 来查找 request 对应的 handler method:
1、首先,通过 directPath 直接获取映射的 handler method
2、如果通过 directPath 没有找到的话,就循环 registry 中所有的映射,查出映射关系
3、如果获取到的映射的 handler 个数 > 1 的话,就找出最合适的匹配
对于 url 映射中的通配符、ant 风格的请求,都是通过 RequestCondition 接口来进行处理的。
相关文章:
【老王读SpringMVC-3】根据 url 是如何找到 controller method 的?
前面分析了 request 与 handler method 映射关系的注册,现在再来分析一下 SpringMVC 是如何根据 request 来获取对应的 handler method 的? 可能有人会说,既然已经将 request 与 handler method 映射关系注册保存在了 AbstractHandlerMethodMapping.Ma…...
人机交互到艺术设计及玫瑰花绘制实例
Python库之图形用户界面 Riverbank Computing | Introduction Welcome to wxPython! | wxPython Overview — PyGObject Python库之游戏开发 https://www.pygame.org/news Panda3D | Open Source Framework for 3D Rendering & Games python.cocos2d.org Python库之…...
多臂老虎机问题
1.问题简介 多臂老虎机问题可以被看作简化版的强化学习问题,算是最简单的“和环境交互中的学习”的一种形式,不存在状态信息,只有动作和奖励。多臂老虎机中的探索与利用(exploration vs. exploitation)问题一直以来都…...
DNS 查询原理详解
DNS(Domain Name System)是互联网上的一种命名系统,它将域名转换为IP地址。在进行DNS查询时,先要明确需要查询的主机名,然后向本地DNS服务器发出查询请求。 1. 本地DNS服务器查询 当用户在浏览器中输入一个URL或者点…...
浅谈软件测试工程师的技能树
软件测试工程师是一个历史很悠久的职位,可以说从有软件开发这个行业以来,就开始有了软件测试工程师的角色。随着时代的发展,软件测试工程师的角色和职责也在悄然发生着变化,从一开始单纯的在瀑布式开发流程中担任测试阶段的执行者…...
转型产业互联网,新氧能否再造辉煌?
近年来,“颜值经济”推动医美行业快速发展,在利润驱动下,除了专注医美赛道的企业之外,也有不少第三方互联网平台正强势进入医美领域,使以新氧为代表的医美企业面对不小发展压力,同时也展现出强大的发展韧性…...
CRE66365 应用资料
CRE66365是一款高度集成的电流模式PWM控制IC,为高性能、低待机功耗和低成本的隔离型反激转换器。在正常负载条件下,AC输入高电压下工作在QR模式。为了最大限度地减少开关损耗,QR 模式下的最大开关频率被内部限制为 77kHz。当负载较低时&#…...
vue3快速上手学习笔记,还不快来看看?
Vue3快速上手 1.Vue3简介 2020年9月18日,Vue.js发布3.0版本,代号:One Piece(海贼王)耗时2年多、2600次提交、30个RFC、600次PR、99位贡献者github上的tags地址:https://github.com/vuejs/vue-next/release…...
HDU 5927 Auxiliary Set
原题链接: https://acm.hdu.edu.cn/showproblem.php?pid5927 题意: 有一颗根节点是1的树,其中有重要的点和不重要的点,重要的点需满足以下两个条件至少一个: 1.本来就是重要的点 2.是两个重要的点的最近共同祖先 有t…...
24:若所有参数皆需类型转换,请为此采用non-member函数
令class支持隐式类型转换通常是个糟糕的主意。 这条规则有其例外,最常见的例外是在建立数值类型时。 例,假设你设计一个class用来表现有理数,则允许整数“隐式转换”为有理数就很合理。 class Rational{ public:Rational(int numerator0,i…...
CMake(2)-详解-编译-安装-支持GDB-添加环境检查-添加版本号-生成安装包
目录 1.什么是CMake 1.1 编译流程CMakeLists.txt a) 最简单 demo1 b) 常用demo2 c) 单目录,源文件-输出文件 DIR_SRCS中 d)多目录,多源文件 1.2.执行命令: 1.3.自定义编译选项 2.安装和测试 3.支持GDB 4.添加环境检查 5.添加…...
java面试题(redis)
目录 1.redis主要消耗什么物理资源? 2.单线程为什么快 3.为什么要使用Redis 4.简述redis事务实现 5.redis缓存读写策略 6.redis除了做缓存,还能做些什么? 7.redis主从复制的原理 8.Redis有哪些数据结构?分别有哪些典型的应…...
Vue组件懒加载
组件懒加载 前言 组件懒加载最常用于异步加载大型/复杂组件或在需要时才进行加载 Vue 2和Vue 3均支持组件懒加载,本文将介绍如何在Vue 2和Vue 3中实现组件懒加载,和一些使用场景 1️⃣方法一:使用Webpack的代码分割能力 Vue 2和Vue 3都可以…...
Qt音视频开发42-网络推流(视频推流/本地摄像头推流/桌面推流/网络摄像头转发推流等)
一、前言 上次实现的文件推流,尽管优点很多,但是只能对现在存在的生成好的音视频文件推流,而现在更多的场景是需要将实时的视频流重新推流分发,用户在很多设备比如手机/平板/网页/电脑/服务器上观看,这样就可以很方便…...
更简单的存取Bean方式-@Bean方法注解
1.Bean方法存储 类注解是添加在某个类上的,那么方法注解是添加在某个方法前的 public class UserBeans {Beanpublic User user1(){User user new User();user.setUid(001);user.setUname("zhangsan");user.setAge(19);user.setPassword("123123");retur…...
边缘计算与AI布署应用电力物联网解决方案-RK3588开发平台
电力行业拥有规模庞大的各类设备,如电表、各类保护、采集、控制设备。面对分布式发电、储能、用户微网等一系列综合问题,边缘计算与AI布署可满足“端侧本地化”高效运用的需求,协助提升最后一公里运行效率。 瑞芯微RK3588J、内置独立NPU&…...
centos部署unity accelerator
参考 https://docs.unity3d.com/Manual/UnityAccelerator.html 方案1:下载Unity Accelerator 手动安装, unity-accelerator-app-v1.0.941g6b39b61.AppImage为下载的文件 1、放入服务器目录, chmod x unity-accelerator-app-v1.0.941g6b39b61.AppImage 2…...
HANA开发指南
建模方面 1、建模方式:图像化建模、SQL建模、CE语言建模 2、维护:SQL和CE比图形化建模更容易维护和修改 3、性能:图形化和CE会经过系统优化,性能一般优于SQL语言 4、可按需要设置参数、变量、Hierachy、聚合类型等 5、在S4系…...
请问你见过吐代码的泡泡吗(冒泡排序)
🤩本文作者:大家好,我是paperjie,感谢你阅读本文,欢迎一建三连哦。 🥰内容专栏:这里是《算法详解》,笔者用重金(时间和精力)打造,将算法知识一网打尽,希望可以…...
【VM服务管家】VM4.0平台SDK_2.1环境配置类
目录 2.1.1 环境配置:CSharp二次开发环境配置方法2.1.2 环境配置:Qt二次开发环境配置方法2.1.3 环境配置:MFC二次开发环境配置方法2.1.4 环境配置:VB.Net二次开发环境配置方法2.1.5 环境配置:运行出现Vm.Core.Solution…...
工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...
【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...
前端导出带有合并单元格的列表
// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...
深入理解JavaScript设计模式之单例模式
目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式(Singleton Pattern&#…...
Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)
笔记整理:刘治强,浙江大学硕士生,研究方向为知识图谱表示学习,大语言模型 论文链接:http://arxiv.org/abs/2407.16127 发表会议:ISWC 2024 1. 动机 传统的知识图谱补全(KGC)模型通过…...
有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...
Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案
在大数据时代,海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构,在处理大规模数据抓取任务时展现出强大的能力。然而,随着业务规模的不断扩大和数据抓取需求的日益复杂,传统…...
LCTF液晶可调谐滤波器在多光谱相机捕捉无人机目标检测中的作用
中达瑞和自2005年成立以来,一直在光谱成像领域深度钻研和发展,始终致力于研发高性能、高可靠性的光谱成像相机,为科研院校提供更优的产品和服务。在《低空背景下无人机目标的光谱特征研究及目标检测应用》这篇论文中提到中达瑞和 LCTF 作为多…...
