SpringMVC源码-AbstractHandlerMethodMapping处理器映射器将@Controller修饰类方法存储到处理器映射器

SpringMVC九大内置组件之HandlerMapping处理器映射器-AbstractHandlerMethodMapping类以及子类RequestMappingHandlerMapping如何将@Controller修饰的注解类以及类下被注解RequestMapping修饰的方法存储到处理器映射器中。

在这里插入图片描述
从RequestMappingHandlerMapping寻找:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
AbstractHandlerMethodMapping类的mappingRegistry什么时候赋值的呢?

AbstractHandlerMethodMapping类以及子类RequestMappingHandlerMapping的类关系图如下,实现了InitializingBean接口,那么该映射器在SpringMVC容器中进行9大组件初始化的时候肯定会调用该afterPropertiesSet方法。

在这里插入图片描述
调用链路如下,在启动项目的时候,先进行Spring父容器的刷新,然后进行SpringMVC子容器的刷新,在子容器中监听器会进行调用9大组件初始化代码(initStrategies)。初始化 HandlerMapping:映射器(initHandlerMappings),配置文件没有配置就获取默认的,实例化属性填充之后进行初始化的设置,调用InitializingBean接口。开始完成@Controller注解进行方法和controller的映射关系,便于在后续进行http接口调用的时候,根据请求路径找到方法名从而获取到对行的controller类去执行方法

InitializingBean接口的afterPropertiesSet方法:200, RequestMappingHandlerMapping (org.springframework.web.servlet.mvc.method.annotation)
invokeInitMethods:2352, AbstractAutowireCapableBeanFactory (org.springframework.beans.factory.support)
调用初始化方法,先调用bean的InitializingBean接口方法,后调用bean的自定义初始化方法 initializeBean:2261, 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)
getDefaultStrategies:925, DispatcherServlet (org.springframework.web.servlet)
初始化 HandlerMapping:映射器,用来将对应的request跟controller进行对应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, 1316528462 (sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$$Lambda$25)
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)

去父类AbstractHandlerMethodMapping类中去调用
在这里插入图片描述
在初始化时检测处理程序方法。
在这里插入图片描述
扫描ApplicationContext中的bean,检测和注册处理程序方法
在这里插入图片描述
判断 Bean 是否为处理器(例如有 @Controller 或者 @RequestMapping 注解)
在这里插入图片描述

	@Overrideprotected boolean isHandler(Class<?> beanType) {// 判断是否有 @Controller 或者 @RequestMapping 的注解return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));}

找到controller类上的方法去存储到处理器映射器中:
在这里插入图片描述

	/*** Uses method and type-level @{@link RequestMapping} annotations to create* the RequestMappingInfo.* @return the created RequestMappingInfo, or {@code null} if the method* does not have a {@code @RequestMapping} annotation.* @see #getCustomMethodCondition(Method)* @see #getCustomTypeCondition(Class)*/@Override@Nullableprotected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {// 基于方法上的 @RequestMapping 注解,创建 RequestMappingInfo 对象RequestMappingInfo info = createRequestMappingInfo(method);if (info != null) {// 基于类上的 @RequestMapping 注解,合并进去RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);if (typeInfo != null) {info = typeInfo.combine(info);}// 如果有前缀,则设置到 info 中String prefix = getPathPrefix(handlerType);if (prefix != null) {info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);}}return info;}
	/*** Delegates to {@link #createRequestMappingInfo(RequestMapping, RequestCondition)},* supplying the appropriate custom {@link RequestCondition} depending on whether* the supplied {@code annotatedElement} is a class or method.* @see #getCustomTypeCondition(Class)* @see #getCustomMethodCondition(Method)*/@Nullableprivate RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {// 获得 @RequestMapping 注解RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);// 获得自定义的条件。目前都是空方法,可以无视RequestCondition<?> condition = (element instanceof Class ?getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));// 基于 @RequestMapping 注解,创建 RequestMappingInfo 对象return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);}

getMappingForMethod方法中调用createRequestMappingInfo方法,完成从类中筛选有RequestMapping注解修饰的方法存储到处理器映射器中

RequestMappingHandlerMapping的registerHandlerMethod

protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {super.registerHandlerMethod(handler, method, mapping);updateConsumesCondition(mapping, method);}

AbstractHandlerMethodMapping的registerHandlerMethod

protected void registerHandlerMethod(Object handler, Method method, T mapping) {this.mappingRegistry.register(mapping, handler, method);}

AbstractHandlerMethodMapping的register

		/*** 释放读锁** Release the read lock after using getMappings and getMappingsByUrl.*/public void releaseReadLock() {this.readWriteLock.readLock().unlock();}public void register(T mapping, Object handler, Method method) {// Assert that the handler method is not a suspending one.if (KotlinDetector.isKotlinType(method.getDeclaringClass())) {Class<?>[] parameterTypes = method.getParameterTypes();if ((parameterTypes.length > 0) && "kotlin.coroutines.Continuation".equals(parameterTypes[parameterTypes.length - 1].getName())) {throw new IllegalStateException("Unsupported suspending handler method detected: " + method);}}// 获得写锁this.readWriteLock.writeLock().lock();try {// 创建HandlerMethod对象HandlerMethod handlerMethod = createHandlerMethod(handler, method);// 校验当前mapping是否存在对应的HandlerMethod对象,如果已存在但不是当前的handlerMethod对象则抛出异常validateMethodMapping(handlerMethod, mapping);// 将mapping与handlerMethod的映射关系保存至this.mappingLookupthis.mappingLookup.put(mapping, handlerMethod);// 获得mapping对应的普通URL数组List<String> directUrls = getDirectUrls(mapping);// 将url和mapping的映射关系保存至this.urlLookupfor (String url : directUrls) {this.urlLookup.add(url, mapping);}// 初始化nameLookupString name = null;if (getNamingStrategy() != null) {// 获得Mapping的名字name = getNamingStrategy().getName(handlerMethod, mapping);// 将mapping的名字与HandlerMethod的映射关系保存至this.nameLookupaddMappingName(name, handlerMethod);}// 初始化CorsConfiguration配置对象CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);if (corsConfig != null) {this.corsLookup.put(handlerMethod, corsConfig);}// 创建MappingRegistration对象// 并与mapping映射添加到registry注册表中this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));}finally {// 释放写锁this.readWriteLock.writeLock().unlock();}}

在这里插入图片描述
submit方法对应的FlashMapController存在映射器了,其他@Controller修饰的注解处理过程一样。
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言VS实用调试技巧

文章目录 一、什么是bug?二、什么是调试&#xff1f;三、Debug和Release四、VS调试快捷键4.1环境准备4.2调试快捷键 五、监视和内存观察5.1监视5.2内存 六、调试举例七、编程常见错误归类7.1编译型错误7.2链接型错误7.3运行时错误 一、什么是bug? &#x1f34e;bug本意是 “…

前端——切换轮播图

学完前端js小知识后&#xff0c;动手操作的一个简单图片轮播图。 <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><meta name"keywords" content"关键词信息"><meta name"des…

MATLAB绘图基础9:多变量图形绘制

参考书&#xff1a;《 M A T L A B {\rm MATLAB} MATLAB与学术图表绘制》(关东升)。 9.多变量图形绘制 9.1 气泡图 气泡图用于展示三个或更多变量变量之间的关系&#xff0c;气泡图的组成要素&#xff1a; 横轴( X {\rm X} X轴)&#xff1a;表示数据集中的一个变量&#xff0c…

带徒实训项目实战讲义分享:ApiFirst文档对比功能页面开发2

前一篇&#xff1a;带徒实训项目实战讲义分享&#xff1a;ApiFirst文档对比功能页面开发 亲爱的学员朋友们好&#xff0c;本小节跟小卷一起来学习用thymeleaf模板技术来渲染数据模型到表格中&#xff0c;通过本小节的学习&#xff0c;你会真正将thymeleaf模板技术应用到实处&a…

Qt获取本机Mac地址、Ip地址

一、简述 今天给大家分享一个获取本机IP地址和Mac地址的方法&#xff0c;经过多次测试&#xff0c;台式机、笔记本等多个设备&#xff0c;暂时没有发现问题。 由于很多时候本地安装了虚拟机、蓝牙、无线网卡或者其他设备等&#xff0c;会有多个Mac地址&#xff0c;所以需要进…

汽车信息安全 -- 存到HSM中的密钥还需包裹吗?

目录 1.车规芯片的ROM_KEY 2.密钥加密与包裹 3.瑞萨RZ\T2M的密钥导入 4.小结 在车控类ECU中&#xff0c;我们通常把主控芯片MCU中的HSM以及HSM固件统一看做整个系统安全架构的信任根。 所以大家默认在HSM内部存储的数据等都是可信的&#xff0c;例如CycurHSM方案中使用HSM…

ControlGAN:Controllable Text-to-Image Generation

1 研究目的 当前的生成网络通常是不可控的&#xff0c;这意味着如果用户更改句子的某些单词&#xff0c;合成图像将与原始文本生成的合成图像显着不同&#xff1b;当给定的文本描述&#xff08;例如颜色&#xff09;发生变化时&#xff0c;鸟类的相应视觉属性被修改&#xff0c…

easyexcel常见问题分析

文章目录 一、读取数字多了很多小数位的精度问题 一、读取数字多了很多小数位的精度问题 浮点型转成BigDecimal的时候会出现精度问题&#xff0c;例如 这儿设置的实体类对象类型是String&#xff0c;默认用到的是StringNumberConverter转换器 2.1.4 版本 public class Strin…

【无人机设计与技术】四旋翼无人机的建模

摘要 本项目的目标是通过 Simulink 建模和仿真&#xff0c;研究四旋翼无人机的建模、姿态控制、定点位置控制及航点规划功能。无人机建模包含了动力单元模型、控制效率模型和刚体模型&#xff0c;并运用这些模型实现了姿态控制和位置控制。姿态控制为无人机的平稳飞行提供基础…

计算机视觉实战项目4(图像分类+目标检测+目标跟踪+姿态识别+车道线识别+车牌识别+无人机检测+A*路径规划+单目测距与测速+行人车辆计数等)

往期热门项目回顾&#xff1a; 计算机视觉项目大集合 改进的yolo目标检测-测距测速 路径规划算法 图像去雨去雾目标检测测距项目 交通标志识别项目 yolo系列-重磅yolov9界面-最新的yolo 姿态识别-3d姿态识别 深度学习小白学习路线 AI健身教练-引体向上-俯卧撑计数…

在VMware虚拟机上部署polardb

免密登录到我们的虚拟机之后&#xff0c;要在虚拟机上部署polardb数据库&#xff0c;首先第一步要先克隆源码&#xff1a; 为了进SSH协议进行传输源码需要先进行下面的步骤&#xff1a; 将宿主机上的私钥文件复制到虚拟机上 scp "C:\Users\waitw\.ssh\id_rsa" ann…

ThinkPHP发送邮件教程:从配置到发送指南!

ThinkPHP发送邮件功能实现策略&#xff1f;Thinkphp如何发邮件&#xff1f; ThinkPHP作为一个流行的PHP框架&#xff0c;提供了强大的邮件发送功能&#xff0c;使得开发者可以轻松地在应用中集成邮件发送功能。AokSend将详细介绍如何在ThinkPHP中配置和发送邮件。 ThinkPHP发…

【Linux-基础IO】如何理解Linux下一切皆文件磁盘的介绍

目录 如何理解Linux系统上一切皆文件 1.物理角度认识磁盘 2.对磁盘的存储进行逻辑抽象 磁盘寻址 3.磁盘中的寄存器 如何理解Linux系统上一切皆文件 计算机中包含大量外设&#xff0c;操作系统想要管理好这些外设&#xff0c;就必须对这些外设进行先描述再组织&#xff0c…

【Linux 23】线程池

文章目录 &#x1f308; 一、线程池的概念&#x1f308; 二、线程池的应用场景&#x1f308; 三、线程池的实现 &#x1f308; 一、线程池的概念 线程池 (thread pool) 是一种利用池化技术的线程使用模式。 虽然创建线程的代价比创建进程的要小很多&#xff0c;但小并不意味着…

一篇文章快速学会docker容器技术

目录 一、Docker简介及部署方法 1.1Docker简介 1.1.1什么是docker 1.1.2 docker在企业中的应用场景 1.1.3 docker与虚拟化的对比 1.1.4 docker的优势 二 、部署docker 2.1 容器工作方法 2.2 部署第一个容器 2.2.1 配置软件仓库 2.2.2 安装docker-ce并启动服务 2.2.…

【AIGC】ChatGPT提示词解析:如何生成爆款标题、节日热点文案与完美文字排版

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AIGC | ChatGPT 文章目录 &#x1f4af;前言&#x1f4af;情绪化的吸睛爆款标题提示词使用方法 &#x1f4af;紧跟节日热点选题文案提示词使用方法 &#x1f4af;高效文字排版技巧提示词使用方法 &#x1f4af;小结 &#x1f4af…

数据结构-链表笔记

移除节点 203. 移除链表元素 - 力扣&#xff08;LeetCode&#xff09; /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val val; }* ListNode(int val, ListN…

Oracle数据库体系结构基础

关于Oracle体系结构 基于Oracle11g体系结构 目标&#xff1a; 了解Oracle体系结构掌握逻辑存储结构掌握物理存储结构熟悉Oracle服务器结构熟悉常用的数据字典 Oracle数据库管理中的重要的三个概念 实例&#xff08;instance):实例是指一组Oracle后台进程以及在服务器中分配…

安宝特分享 | AR技术重塑工业:数字孪生与沉浸式培训的创新应用

在数字化转型的浪潮中&#xff0c;AR&#xff08;增强现实&#xff09;技术与工业的结合正在呈现新的趋势和应用延伸。特别是“数字孪生”概念的崛起&#xff0c;为AR技术在工业中提供了独特而创新的切入点。 本文将探索AR如何与数字孪生、沉浸式体验和实用案例相结合&#xf…

ResNet50V2:口腔癌分类

本文为为&#x1f517;365天深度学习训练营内部文章 原作者&#xff1a;K同学啊 一 ResNet和ResNetV2对比 改进点&#xff1a;(a)original表示原始的ResNet的残差结构&#xff0c;(b)proposed表示新的ResNet的残差结构&#xff0c;主要差别就是(a)结构先卷积后进行BN和激活函数…