带着问题阅读源码——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是字符串类型,则将其转换为对应的类类型。
java 复制代码
	Class<?> handlerType = (handler instanceof String ?
				obtainApplicationContext().getType((String) handler) : handler.getClass());
  • 检测handler的方法:遍历handler的所有方法,检测哪些方法带有特定的注解(如@RequestMapping),这些方法被视为处理器方法。
java 复制代码
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);
						}
					});
  • 注册处理器方法:将检测到的处理器方法注册到映射器中,这样当接收到请求时,映射器就可以根据请求的信息找到对应的处理器方法来处理请求。
java 复制代码
			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 接口来执行不同类型的处理器,而不需要了解具体的实现细节。
相关推荐
EXI-小洲6 小时前
Java 操作 Word:字符串替换、图片插入、动态生成表格与API接口下载
java·开发语言·spring boot·word
2601_961901707 小时前
SpringBoot使用Nacos进行application.yml配置管理
java·spring boot·spring
何以解忧,唯有..7 小时前
LangChain 工具调用(Tool Calling)实战指南
java·前端·langchain
QQ_21696290968 小时前
【源码编号:project79475】SpringBoot校内二手交易平台:商品发布、分类检索、留言交流、订单管理全流程实战
java·spring boot·后端
前端 贾公子9 小时前
第09章:上下文与记忆 (2)
java·服务器·前端
2601_962203519 小时前
Java进阶07集合(续)
java·开发语言
郑州光合科技余经理9 小时前
本地生活服务系统:模块边界与结算字段怎么拆
java·开发语言·前端·后端·系统架构·uni-app·php
专注仿真10 小时前
Spring AI 实现智能对话系统项目指南
数据结构·spring·机器学习
roman_日积跬步-终至千里10 小时前
【数据治理(6)】DataOps 不是调度工具,而是让数据产品长期可信的运行机制
java·服务器·网络
落魄大学生之流水线上谋生计10 小时前
LangGraph 基本用法指南
java·windows·python·langchain