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

news2024/9/30 16:38:50

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 注解)
在这里插入图片描述

	@Override
	protected 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
	@Nullable
	protected 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)
	 */
	@Nullable
	private 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.mappingLookup
				this.mappingLookup.put(mapping, handlerMethod);

				// 获得mapping对应的普通URL数组
				List<String> directUrls = getDirectUrls(mapping);
				// 将url和mapping的映射关系保存至this.urlLookup
				for (String url : directUrls) {
					this.urlLookup.add(url, mapping);
				}

				// 初始化nameLookup
				String name = null;
				if (getNamingStrategy() != null) {
					// 获得Mapping的名字
					name = getNamingStrategy().getName(handlerMethod, mapping);
					// 将mapping的名字与HandlerMethod的映射关系保存至this.nameLookup
					addMappingName(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.coloradmin.cn/o/2180126.html

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

相关文章

②三菱Modbus主站MELSEC转ModbusRTU/ASCII工业MELSEC网关串口服务

三菱Modbus主站MELSEC转ModbusRTU/ASCII工业MELSEC网关串口服务https://item.taobao.com/item.htm?ftt&id834634632647 MELSEC 通信单元 MELSEC 转 RS485 &#xff08;接上一章&#xff09; 动作指示灯 电源指示灯(PWR) 表示 MS-A1-80X1 通讯模块是否处于通电中。…

用ChatGPT工作提效,这些方法太实用了!

被任务和紧迫的截止日期压垮了吗&#xff1f;ChatGPT 是提升工作效率的关键武器。探索这篇指南&#xff0c;快速提升您的工作效率&#xff01; ChatGPT 在现代职场中的角色 随着数字时代的到来&#xff0c;技术进步彻底改变了商业世界&#xff0c;自动化和效率已成为企业保持…

怎样才能设计出全面且详细的测试要点?

今天想跟大家分享一个案例&#xff0c;关于一个测试场景引发的测试要点思考。 废话不多说&#xff0c;上菜&#xff01; 情况介绍 某天&#xff0c;开发同事提交了一个功能优化单&#xff0c;大概情况就是&#xff1a;为了节省内存使用&#xff0c;开启了一个配置&#xff0…

求解线性方程的方法步骤(含例题),附解线性方程计算器

大家好&#xff0c;这里是效率办公指南&#xff01; &#x1f4d0; 在数学和工程问题中&#xff0c;线性方程是一类非常基础且常见的问题。无论是解决简单的一元一次方程&#xff0c;还是复杂的多元线性方程组&#xff0c;都有一定的方法和步骤可以遵循。今天&#xff0c;我们…

体育课评分系统小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;学生管理&#xff0c;点明册管理&#xff0c;体育教案管理&#xff0c;教学评分管理&#xff0c;学生心率管理&#xff0c;身体素质测评管理&#xff0c;教学比赛成绩管理 微信端账号功能包括&#xf…

Autosar CP系列:设计模式之仲裁模式和信号质量模式

本文讲解关于Autosar的另外两个设计模式&#xff1a;仲裁模式和信号质量模式&#xff0c;上篇花大量篇幅讲解了《传感器执行器模式》。 1.仲裁模式 为了解决多个不同提供者或请求者之间的仲裁问题&#xff0c;引入一个新的组件&#xff0c;这个组件的作用是管理所有来自不同请…

安防监控/智慧安防EasyCVR视频汇聚监控平台无法启动并报错“no space left on service”是什么原因?

视频汇聚/安防监控/智慧安防EasyCVR视频监控平台&#xff0c;作为一款智能视频监控综合管理平台&#xff0c;凭借其强大的视频融合汇聚能力和灵活的视频能力&#xff0c;在各行各业的应用中发挥着越来越重要的作用。平台可以引入AI智能分析能力&#xff0c;能够实现对视频中的特…

Spring Cloud面试题收集

Spring Cloud Spring cloud 是一系列框架的有序集合。它利用 spring boot 的开发便利性巧妙地简化了分布式系统基础设施的开发&#xff0c;如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等&#xff0c;都可以用 spring boot 的开发风格做到一键启动和部署。…

基于SpringBoot - Netty框架的云快充协议(充电桩协议)

云快充协议是一种标准通信协议&#xff0c;主要用于电动车与充电桩之间的数据交换。该协议包含了充电请求、状态查询、支付等多个功能模块。这些功能的实现不仅需要对协议进行深入理解&#xff0c;还需要编写相应的代码进行封装。 软件架构 1、提供云快充底层桩直连协议&#…

“DNA亲和纯化测序:汇智生物的精准分析“

&#x1f331; 汇智生物 | 专注农业&植物基因组分析 &#x1f331; &#x1f393; 教授【优青】团队亲自指导&#xff01;提供专业实验设计、数据分析、SCI论文辅助等全方位服务。精准高效&#xff0c;为农植物科研保驾护航&#xff01; &#x1f52c; 专业实验外包服务&am…

100个超有用的Python知识点!

一、基础语法 1.变量的定义与赋值。 2.不同数据类型&#xff08;整数、浮点数、字符串、布尔值、列表、元组、字典、集合&#xff09;的使用。 3.运算符&#xff08;算术、比较、逻辑、赋值、位运算等&#xff09;。 4.控制流语句&#xff08;if-else、for 循环、while 循环…

IDEA 最新版创建 Sping Boot 项目没有 JDK8 选项的解决方案

问题 今天新建一个 Java 项目写 demo 时&#xff0c;发现 Idea 上只能勾选 Java 17、21、23 三个版本 解决方案 IDEA 页面创建 Spring 项目&#xff0c;其实是访问 spring initializr 去创建项目。我们可以通过阿里云国服去间接创建 Spring 项目。服务器 URL 地址替换为 ht…

如何将list嵌套的list的[]去掉

如果list里里面的元素是数字&#xff0c;‘1’也是可以的&#xff0c;那么我们可以使用np.ravel a [[1,2,3], [5, 2, 8], [7,8,9]]list(np.ravel(a)) #[1, 2, 3, 5, 2, 8, 7, 8, 9]对于不规则List c[[‘云阳站’], [‘双江’, ‘木古’], [‘滨双线’], [‘滨双线’, ‘云田线…

【Echarts地图开发全流程加全套代码】

前言 本篇分享近期做的项目echarts相关地图开发的相关细节和避坑细节&#xff01;&#xff01; 一、地图Json文件 echarts地图采用官网的type类型map进行配置开发 Apache EChartsApache ECharts&#xff0c;一款基于JavaScript的数据可视化图表库&#xff0c;提供直观&…

Excel中查找某个值的位置,用位置取值

有 2022 年 1 月的日销售额统计表如下所示&#xff1a; 找出销售额最大的是哪一天&#xff0c;在 C2 单元格里输入&#xff1a; spl("E(?1).pmax(Sales)",A1:B32)返回结果 12 接着找出销售额最大的那天的前 5 天和后 5 天的销售额&#xff1a; spl("E(?1).…

RAR格式文件解压:适合各平台的RAR解压软件下载推荐

RAR格式是一种广泛使用的压缩格式&#xff0c;因其优秀的压缩率和多样化的功能而受到用户的喜爱。然而&#xff0c;尽管许多操作系统自带基本的压缩解压功能&#xff0c;但要处理RAR格式文件&#xff0c;通常需要借助专门的解压软件。本文将为用户推荐适合Windows、Mac、Linux和…

支付宝“碰一下”微信

“‘碰一下’风头正盛&#xff0c;他们设立了专门的项目组&#xff0c;特别卷&#xff0c;动不动搞到两点&#xff0c;有些受不了的&#xff0c;就主动活水到别的团队了。他们内部也在各种挖人&#xff0c;善攻&#xff08;支付宝副总裁李佳佳的花名&#xff09;为了这个项目拼…

RabbitMQ的高级特性-死信队列

死信(dead message) 简单理解就是因为种种原因, ⽆法被消费的信息, 就是死信. 有死信, ⾃然就有死信队列. 当消息在⼀个队列中变成死信之后&#xff0c;它能被重新被发送到另⼀个交换器 中&#xff0c;这个交换器就是DLX( Dead Letter Exchange ), 绑定DLX的队列, 就称为死信队…

9.30今日错题解析(软考)

目录 前言系统开发基础——需求分析相关概念及需求的分类面向对象技术——UML图的图示面向对象技术——面向对象的基本概念 前言 这是用来记录我备考软考设计师的错题的&#xff0c;今天知识点为需求分析相关概念及需求的分类、UML图的图示、面向对象的基本概念&#xff0c;大…

《Windows PE》3.2 PE头结构-DOS头和DOS块

正如我们在初识PE文件一节中看到的&#xff0c;PE文件头中包含几个重要的结构&#xff0c;DOS头、DOS块&#xff08;DOS Stub&#xff09;和NT头。NT头就是PE特征码文件头&#xff08;COFF 文件标头&#xff09;扩展头&#xff08;可选标头&#xff09;&#xff0c;合称为NT头。…