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

news2024/11/17 8:30:46

背景

在 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 接口来执行不同类型的处理器,而不需要了解具体的实现细节。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

设计模式-结构型模式-外观模式

外观模式&#xff08;Facade&#xff09;&#xff0c;为子系统中的一组接口提供一个一致的界面&#xff0c;此模式定义了一个高层接口&#xff0c;这个接口使得这一子系统更加容易使用。[DP] 首先&#xff0c;定义子系统的各个组件接口和具体实现类&#xff1a; // 子系统组件接…

MySQL 用了哪种默认隔离级别,实现原理是什么?

MySQL 的默认隔离级别是 RR - 可重复读&#xff0c;可以通过命令来查看 MySQL 中的默认隔离级别。 RR - 可重复读是基于多版本并发控制&#xff08;Multi-Version Concurrency Control&#xff0c;MVCC &#xff09;实现的。MVCC&#xff0c;在读取数据时通过一种类似快照的方…

if语句用法

if语句是单条件分支语句 定义&#xff1a;根据一个条件来控制程序执行流程(如图3.2)。 语法格式&#xff1a; if&#xff08;表达式&#xff09;{ 若干语句 } ★注意★&#xff1a; ① 表达式的值必须是boolean 型&#xff1b; ② 不能用0代表false&#xff1b;用1代表 true&am…

qt 5.15版本安装

1.qt5.15版本安装 2.安装慢时&#xff0c;切换到清华镜像源&#xff1a;.\qt-unified-windows-x64-online.exe --mirror https://mirrors.tuna.tsinghua.edu.cn/qt/ 3.没有qt 5.15版本在旁边进行筛选&#xff0c;只选archive

MySql外连接

目录 数据准备外连接 数据准备 -- 部门表 create table tb_dept (id int unsigned primary key auto_increment comment 主键ID,name varchar(10) not null unique comment 部门名称,create_time datetime not null comment 创建时间,update_time datetime…

ABB双语言共享充电宝投资理财源码/共享充电宝系统源码/共享充电宝市场分析/五级分销返利+地图显示模式

ABB双语言共享充电宝投资理财源码/五级分销返利地图显示模式/vue编译后前端 测试环境&#xff1a;Linux系统CentOS7.6、宝塔、PHP7.3、MySQL5.6&#xff0c;根目录public&#xff0c;伪静态laravel5&#xff0c; 源码下载&#xff1a;https://download.csdn.net/download/m0_…

2022年CSP-J认证 CCF信息学奥赛C++ 中小学初级组 第一轮真题-完善程序题解析

2022CCF认证第一轮&#xff08;CSP-J&#xff09;真题 三、完善程序题 第一题 枚举因数 从小到大打印正整数n的所有正因数。试补全枚举程序 #include <iostream> using namespace std;int main(){int n;cin >> n;vector<int> fac;fac.reserve((int)ceil(…

备战蓝桥杯---线段树基础1

引入&#xff1a;RMQ问题&#xff1a; 什么是RMQ&#xff1f; 显然&#xff0c;我们无法用前缀维护&#xff0c;因此&#xff0c;我们需要用到线段树的知识&#xff1a; 什么是线段树&#xff1f; 线段树是用一种树状结构存储一个连续区间信息的数据结构 下面我们用图解释用…

2024全国水科技大会暨高氨氮废水厌氧氨氧化处理技术论坛(四)

一、会议背景 为积极应对“十四五”期间我国生态环境治理面临的挑战&#xff0c;加快生态环境科技创新&#xff0c;构建绿色技术创新体系&#xff0c;全面落实科学技术部、生态环境部等部委编制的《“十四五”生态环境领域科技创新专项规划》&#xff0c;积极落实省校合作&…

物联网与智慧城市的融合:构建智能化、便捷化、绿色化的城市未来

一、引言 随着科技的飞速发展和城市化的不断推进&#xff0c;物联网技术正逐步渗透到城市的各个领域&#xff0c;成为推动智慧城市建设的核心力量。物联网与智慧城市的融合&#xff0c;不仅为城市治理提供了高效、智能的解决方案&#xff0c;也为市民的生活带来了前所未有的便…

Docker Swarm全解析:实现微服务高可用与故障转移的秘密武器

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《Docker入门到精通》 《k8s入门到实战》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、基本概念和介绍 1、Docker Swarm 是什么&#xff0c;它与 …

APP自动化测试-入门示例

入门示例 通过上一篇博客APP自动化测试介绍-CSDN博客的学习&#xff0c;相信大家对APP自动化测试已经有了一定的了解&#xff0c;下面演示一下入门示例 1. 配置Appium 1.1. 点击Appium图标&#xff0c;打开服务器&#xff1a; 1.2. 点击Edit Configurations,进入配置页面&am…

elment-ui table表格排序后 清除排序箭头/恢复默认排序 的高亮样式

问题描述&#xff1a; 1.默认排序是按照名称升序排列&#xff08;图一&#xff09; 2.在选择了筛选项以及其他排序方式之后&#xff0c;箭头高亮是这样的&#xff08;图二&#xff09; 3.当我点击清空按钮后&#xff0c;类型清空了&#xff0c;并且传给后端的排序方式是名称/升…

文本多分类

还在用BERT做文本分类&#xff1f;分享一套基于预训练模型ERNIR3.0的文本多分类全流程实例【文本分类】_ernir 文本分类-CSDN博客 /usr/bin/python3 -m pip install --upgrade pip python3-c"import platform;print(platform.architecture()[0]);print(platform.machine…

StarRocks实战——表设计规范与监控体系

目录 前言 一、StarRocks表设计 1.1 字段类型 1.2 分区分桶 1.2.1 分区规范 1.2.2 分桶规范 1.3 主键表 1.3.1 数据有冷热特征 1.3.2 大宽表 1.4 实际案例 1.4.1 案例一&#xff1a;主键表内存优化 1.4.2 案例一&#xff1a;Update内存超了&#xff0c;导致主键表导…

【AI Agent系列】【MetaGPT多智能体学习】5. 多智能体案例拆解 - 基于MetaGPT的智能体辩论(附完整代码)

本系列文章跟随《MetaGPT多智能体课程》&#xff08;https://github.com/datawhalechina/hugging-multi-agent&#xff09;&#xff0c;深入理解并实践多智能体系统的开发。 本文为该课程的第四章&#xff08;多智能体开发&#xff09;的第三篇笔记。主要是对课程刚开始环境搭…

YOLOv9有效提点|加入SE、CBAM、ECA、SimAM等几十种注意力机制(一)

专栏介绍&#xff1a;YOLOv9改进系列 | 包含深度学习最新创新&#xff0c;主力高效涨点&#xff01;&#xff01;&#xff01; 一、本文介绍 本文将以SE注意力机制为例&#xff0c;演示如何在YOLOv9种添加注意力机制&#xff01; 《Squeeze-and-Excitation Networks》 SENet提出…

【六袆 - React】Next.js:React 开发框架;Next.js开发框架的特点

Next.js&#xff1a;React 开发框架 Next.js的特点 1.直观的、基于页面的路由系统&#xff08;并支持动态路由&#xff09; Next.js 提供了基于文件系统的路由&#xff0c;意味着你可以通过创建页面文件来定义路由。 伪代码示例&#xff1a; // pages/index.js export defa…

css【详解】—— 圣杯布局 vs 双飞翼布局 (含手写清除浮动 clearfix)

两者功能效果相同&#xff0c;实现方式不同 效果预览 两侧宽度固定&#xff0c;中间宽度自适应&#xff08;三栏布局&#xff09;中间部分优先渲染允许三列中的任意一列成为最高列 圣杯布局 通过左右栏填充容器的左右 padding 实现&#xff0c;更多细节详见注释。 <!DOCTYP…

day03-Vue-Element

一、Ajax 1 Ajax 介绍 1.1 Ajax 概述 概念&#xff1a;Asynchronous JavaScript And XML&#xff0c;异步 的 JavaScript 和 XML。 作用&#xff1a; 数据交换&#xff1a;通过 Ajax 可以给服务器发送请求&#xff0c;并获取服务器响应的数据。异步交互&#xff1a;可以在 不…