带着问题阅读源码——Spring MVC是如何将url注册到RequestMappingHandlerMapping?

背景

在 Spring MVC 中,DispatcherServlet 是前端控制器(front controller),它负责接收所有的 HTTP 请求并将它们映射到相应的处理器(handler)。为了实现这一点,Spring MVC 使用了适配器模式将 Controller 与 DispatcherServlet 绑定在一起。

在Spring MVC的优雅设计中,所有公开的接口默认都通过RequestMappingHandlerMapping进行映射转换。这一过程的核心在于如何将这些接口有效地注册到RequestMappingHandlerMapping。本文将深入探讨这一机制,揭开其背后的原理和细节,这是我们研究的主要焦点。

RequestMappingHandlerMapping介绍

RequestMappingHandlerMapping 是 Spring MVC 中的一个类,用于将请求映射到处理器方法。它是 AbstractHandlerMethodMapping 的一个具体实现,提供了一些默认的请求映射策略。

在 Spring MVC 中,HandlerMapping 负责将请求映射到相应的处理器方法。RequestMappingHandlerMapping 提供了一个基本的框架,可以自定义扩展以支持不同的请求映射方式。例如,可以通过继承RequestMappingHandlerMapping 并重写其中的方法来实现自定义的请求映射策略。

具体来说,RequestMappingHandlerMapping 主要包含以下几个关键部分:

  • registerHandlerMethod 方法:该方法用于注册一个处理器方法。它首先检查该处理器方法是否已经注册过,如果没有则将其添加到内部维护的处理器方法列表中。

  • getHandlerInternal 方法:该方法根据请求信息获取对应的处理器方法。它首先通过lookupHandlerMethod 方法查找匹配的处理器方法,然后通过 instantiateHandlerMethod 方法实例化处理器方法对象。

  • lookupHandlerMethod 方法:该方法根据请求信息查找匹配的处理器方法。它首先通过extractPathWithinApplication 方法提取请求路径中的应用程序路径,然后通过 matches 方法匹配处理器方法。如果找到匹配的处理器方法,则返回该处理器方法;否则返回 null。

  • matches 数组:该方法根据请求信息和处理器方法进行匹配。它首先检查请求路径是否与处理器方法的 URL 模式匹配,然后检查请求方法是否与处理器方法的 HTTP 方法匹配。如果两个条件都满足,则认为匹配成功。

  • handleMatch 方法:该方法处理匹配成功的处理器方法。它首先调用 preHandle 方法进行预处理,然后调用处理器方法执行业务逻辑,最后调用 afterCompletion 方法进行后处理。

注册过程

AbstractHandlerMethodMapping是Spring MVC中用于处理请求映射的抽象类。它提供了一些基本的方法,如获取处理器方法、处理方法参数等。具体的实现类需要继承这个抽象类并实现相应的方法。

AbstractHandlerMethodMapping 中的 detectHandlerMethods 方法是用于从处理器中获取处理器方法并注册的。这个方法是一个受保护的方法,它的作用是检测带有特定注解(如@RequestMapping)的方法,并将这些方法注册到映射器中,以便后续可以根据请求找到对应的处理器方法来处理请求。

具体来说,detectHandlerMethods 方法会执行以下步骤:

  • 获取handler的类型:如果传入的handler是字符串类型,则将其转换为对应的类类型。
	Class<?> handlerType = (handler instanceof String ?
				obtainApplicationContext().getType((String) handler) : handler.getClass());
  • 检测handler的方法:遍历handler的所有方法,检测哪些方法带有特定的注解(如@RequestMapping),这些方法被视为处理器方法。
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
					(MethodIntrospector.MetadataLookup<T>) method -> {
						try {
							return getMappingForMethod(method, userType);
						}
						catch (Throwable ex) {
							throw new IllegalStateException("Invalid mapping on handler class [" +
									userType.getName() + "]: " + method, ex);
						}
					});
  • 注册处理器方法:将检测到的处理器方法注册到映射器中,这样当接收到请求时,映射器就可以根据请求的信息找到对应的处理器方法来处理请求。
			methods.forEach((method, mapping) -> {
				Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
				registerHandlerMethod(handler, invocableMethod, mapping);
			});
		}

调用过程

在这里插入图片描述

在 Spring MVC 中,RequestMappingHandlerMapping 是负责处理基于注解的控制器方法的映射。默认情况下,所有标记有 @RequestMapping 注解的控制器方法都会通过 RequestMappingHandlerMapping 进行注册和处理。这个过程涉及到以下几个关键步骤:

  1. Spring容器启动:
  • 在应用启动时,Spring 容器会初始化所有的单例 Bean,包括 DispatcherServlet 和相关的组件。
  1. 初始化 RequestMappingHandlerMapping:
  • RequestMappingHandlerMapping 实现了 InitializingBean 接口,因此它的 afterPropertiesSet() 方法会在所有属性设置完成后被调用,以完成其初始化工作。
  1. 扫描控制器组件:
  • 在初始化过程中,RequestMappingHandlerMapping 会扫描 Spring 容器中的 Bean,寻找带有 @Controller 注解的类以及带有 @RequestMapping 注解的方法。
  1. 注册映射关系:
  • 对于找到的控制器和方法,RequestMappingHandlerMapping 会将它们的 URL 路径和处理方法之间的映射关系注册到内部的映射注册表中。
  1. 构建URL到方法的映射:
  • RequestMappingHandlerMapping 会解析这些映射信息,构建一个从 URL 到控制器方法的映射表,以便能够快速地根据请求的 URL 找到对应的处理方法。
  1. 处理请求:
  • 当 HTTP 请求到达 DispatcherServlet 时,它会使用 RequestMappingHandlerMapping 来确定请求应该由哪个控制器方法来处理。一旦找到匹配的方法,DispatcherServlet 会使用 RequestMappingHandlerAdapter 来执行该方法。
  1. 适配器模式的应用:
  • 适配器模式在这里确保了 DispatcherServlet 能够通过统一的 HandlerAdapter 接口来执行不同类型的处理器,而不需要了解具体的实现细节。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Atcoder ABC342 E - Last Train

Last Train&#xff08;最后一班火车&#xff09; 时间限制&#xff1a;2s 内存限制&#xff1a;1024MB 【原题地址】 所有图片源自Atcoder&#xff0c;题目译文源自脚本Atcoder Better! 点击此处跳转至原题 【问题描述】 【输入格式】 【输出格式】 【样例1】 【样例输入…

<网络安全>《61 微课堂<第1课 南北向流量是什么?>》

1 形象化解释 在网络安全中&#xff0c;经常听到南北向流量这个词。那究竟是什么意思呢&#xff1f; 这里的南北&#xff0c;就是地图上的东西南北&#xff0c;是方向。我们在画网络架构图时&#xff0c;往往是由上到下依次是web层、应用层、数据层&#xff0c;流量从web层到…

数据结构——跳表

简单介绍跳表 跳表&#xff08;Skip List&#xff09;是一种可以进行对数级别查找的数据结构&#xff0c;它通过在数据中构建多级索引来提高查询效率。跳表是一种基于链表的随机化数据结构&#xff0c;其本质是由多个链表组成&#xff0c;每个链表中的元素都是原始链表中的元素…

图神经网络导论 - 刘知远

一、神经网络基础 近年来&#xff0c;机器学习领域的发展迅速&#xff0c;主要表现在多种神经网络架构的出现。尽管不同的神经网络架构相差甚远&#xff0c;但现有的神经网络架构可以分为几个类别&#xff1a; 卷积神经网路是前馈神经网路的特殊形式&#xff0c;FNN通常是全…

RISC-V特权架构 - 中断与异常概述

RISC-V特权架构 - 中断与异常概述 1 中断概述2 异常概述3 广义上的异常3.1 同步异常3.2 异步异常3.3 常见同步异常和异步异常 本文属于《 RISC-V指令集基础系列教程》之一&#xff0c;欢迎查看其它文章。 1 中断概述 中断&#xff08;Interrupt&#xff09;机制&#xff0c;即…

java实现图片转pdf,并通过流的方式进行下载(前后端分离)

首先需要导入相关依赖&#xff0c;由于具体依赖本人也不是记得很清楚了&#xff0c;所以简短的说一下。 iText&#xff1a;PDF 操作库&#xff0c;用于创建和操作 PDF 文件。可通过 Maven 或 Gradle 引入 iText 依赖。 MultipartFile&#xff1a;Spring 框架中处理文件上传的类…

MyBatis 学习(四)之 SQL 映射文件

目录 1 SQL 映射文件介绍 2 select 元素 3 insert 元素 4 update 和 delete 元素 5 sql 元素 6 parameterType 元素 7 resultType 元素 8 resultMap 元素&#xff08;重要&#xff09; 9 参考文档 1 SQL 映射文件介绍 映射器是 MyBatis 中最复杂并且是最重要的…

机器学习 -- 梯度下降算法加深

梯度下降算法 在机器学习中&#xff0c;梯度下降算法常用于最小化代价函数&#xff08;或损失函数&#xff09;&#xff0c;以此来优化模型的参数。代价函数衡量的是模型预测值与实际值之间的差异。通过最小化这个函数&#xff0c;我们可以找到模型预测最准确的参数。 代价函…

蓝桥杯-单片机组基础6——定时计数器与外部中断混合使用(附小蜜蜂课程代码)

蓝桥杯单片机组备赛指南请查看这篇文章&#xff1a;戳此跳转蓝桥杯备赛指南文章 本文章针对蓝桥杯-单片机组比赛开发板所写&#xff0c;代码可直接在比赛开发板上使用。 型号&#xff1a;国信天长4T开发板&#xff08;绿板&#xff09;&#xff0c;芯片&#xff1a;IAP15F2K6…

Android 混淆是啥玩意儿?

什么是混淆 Android混淆&#xff0c;是伴随着Android系统的流行而产生的一种Android APP保护技术&#xff0c;用于保护APP不被破解和逆向分析。简单的说&#xff0c;就是将原本正常的项目文件&#xff0c;对其类、方法、字段&#xff0c;重新命名a,b,c…之类的字母&#xff0c…

[AutoSar]BSW_Com07 CAN报文接收流程的函数调用

目录 关键词平台说明一、背景二、顺序总览三、函数说明3.1 Com_RxIndication&#xff08;&#xff09; 关键词 嵌入式、C语言、autosar、OS、BSW 平台说明 项目ValueOSautosar OSautosar厂商vector &#xff0c;芯片厂商TI 英飞凌编程语言C&#xff0c;C编译器HighTec (GCC)…

win11安装nodejs

一、下载安装包 链接: https://pan.baidu.com/s/1_df8s1UlgNNaewWrWgI59A?pwdpsjm 提取码: psjm 二、安装步骤 1.双击安装包 2.Next> 3.勾选之后&#xff0c;Next> 4.点击Change&#xff0c;选择你要安装的路径&#xff0c;然后Next> 5.点击Install安装 二、…

MySQL 存储过程批量插入总结

功能需求背景&#xff1a;今天接到产品经理核心业务表的数据压测功能&#xff0c;让我向核心业务表插入百万级的业务量数据&#xff0c;我首先想到的办法就是存储过程实现数据的批量 。 由于无法提供核心业务表&#xff0c;本文仅仅提供我刚刚自己创建的表bds_base_user 表做相…

【Vue3】深入理解Vue中的ref属性

&#x1f497;&#x1f497;&#x1f497;欢迎来到我的博客&#xff0c;你将找到有关如何使用技术解决问题的文章&#xff0c;也会找到某个技术的学习路线。无论你是何种职业&#xff0c;我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章&#xff0c;也欢…

VSCode通过SSH连接Docker环境进行开发

文章目录 VSCode 插件Docker 镜像构建镜像部署环境 VSCode 连接本地Docker容器VSCode SSH连接Docker容器VSCode 打开容器内目录文件 VSCode 插件 Remote - SSH Docker 镜像 https://hub.docker.com/_/golang # Golang 镜像 docker pull golang:1.22构建镜像 Dockerfile F…

Shell条件判断

一、文件类型判断 示例&#xff1a; # 判断文件是否存在&#xff0c;存在为0&#xff0c; 不存在为1 [rootlocalhost ~]# test -e person.txt [rootlocalhost ~]# echo $? 0 [rootlocalhost ~]# [rootlocalhost ~]# test -e aba [rootlocalhost ~]# echo $? 1 # 出test外&am…

SaaS 电商设计 (九) 动态化且易扩展的实现购物车底部弹层(附:一套普适的线上功能切量的发布方案)

目录 一.背景1.1 业务背景1.2 技术负债 二.技术目标三.方案设计3.1 解决移动端频繁发版3.1.1 场景分析3.1.2 技术方案 3.2 减少后端坏味道代码&无法灵活扩展问题3.2.1 通过抽象接口完成各自单独楼层渲染逻辑3.2.2 通过配置能力做到部分字段可配 四.升级上线(普适于高并发大…

小程序实现定位城市切换且城市根据首字母A-Z排序后端数据实现逻辑

场景&#xff1a; 话不多说后端提供数据实现步骤&#xff1a; 1.controller层 Api(tags {"[地区]-城市相关接口"}) RestController RequestMapping("region") Slf4j public class RegionController extends BaseController {Resourceprivate RegionServ…

盲人出行:科技创造美好的未来

在繁忙的都市中&#xff0c;我每天都要面对许多挑战&#xff0c;盲人出行安全保障一直难以得到落实。我看不见这个世界&#xff0c;只能依靠触觉和听觉来感知周围的一切。然而&#xff0c;我从未放弃过对生活的热爱和对未来的憧憬。在一次机缘巧合下&#xff0c;我认识了一款名…

信息系统项目管理师--项目管理概述

开展项⽬是为了通过可交付成果达成⽬标。⽬标是所指向的结果、要取得的战略地位、要达到的⽬的、要获得的成果、要⽣产的产品或者要提供的服务。 可交付成果形成的独特并可验证的产品、成果或服务。可交付成果可能是有形的&#xff0c;也可能是⽆形的。产⽣⼀个或多个可交付成…