SpringMVC源码-@ControllerAdvice和 @InitBinder注解源码讲解

news2024/11/25 7:32:51

1.@ControllerAdvice修饰的类何时被加载扫描

被@ControllerAdvice修饰的类是作用于全局的
initStrategies 初始化springmvc的9大组件

initStrategies:531, 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, 1659438018 (sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$$Lambda$24)
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)

initHandlerAdapters(context); 初始化 HandlerAdapter:处理适配器,主要包含Http请求处理器适配器,简单控制器处理器适配器,注解方法处理器适配器

在这里插入图片描述
循环遍历生成,遍历到RequestMappingHandlerAdapter,类图如下:
在这里插入图片描述
因为实现了InitializingBean接口,当初始化调用afterPropertiesSet方法:
在这里插入图片描述
initControllerAdviceCache 初始化注释了@ControllerAdvice的类的相关属性

	private void initControllerAdviceCache() {
		// 判断当前应用程序上下文是否为空,如果为空,直接返回
		if (getApplicationContext() == null) {
			return;
		}

		// 扫描@ControllerAdvice注解的Bean,生成对应的ControllerAdviceBean对象,并将进行排序
		List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());

		List<Object> requestResponseBodyAdviceBeans = new ArrayList<>();

		// 遍历ControllerAdviceBean数组
		for (ControllerAdviceBean adviceBean : adviceBeans) {
			Class<?> beanType = adviceBean.getBeanType();
			if (beanType == null) {
				throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean);
			}
			// 扫描有`@ModelAttribute`,无`@RequestMapping`注解的方法,添加到`modelAttributeAdviceCache`属性中
			// 该类方法用于在执行方法前修改 Model 对象
			Set<Method> attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);
			if (!attrMethods.isEmpty()) {
				this.modelAttributeAdviceCache.put(adviceBean, attrMethods);
			}
			// 扫描有`@InitBinder`注解的方法,添加到`initBinderAdviceCache`属性中
			// 该类方法用于在执行方法前初始化数据绑定器
			Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS);
			if (!binderMethods.isEmpty()) {
				this.initBinderAdviceCache.put(adviceBean, binderMethods);
			}
			// 如果是RequestBodyAdvice或ResponseBodyAdvice的子类,添加到requestResponseBodyAdviceBeans中
			if (RequestBodyAdvice.class.isAssignableFrom(beanType) || ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
				requestResponseBodyAdviceBeans.add(adviceBean);
			}
		}

		// 将requestResponseBodyAdviceBeans添加到this.requestResponseBodyAdvice属性中
		if (!requestResponseBodyAdviceBeans.isEmpty()) {
			this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);
		}

		// 打印日志
		if (logger.isDebugEnabled()) {
			int modelSize = this.modelAttributeAdviceCache.size();
			int binderSize = this.initBinderAdviceCache.size();
			int reqCount = getBodyAdviceCount(RequestBodyAdvice.class);
			int resCount = getBodyAdviceCount(ResponseBodyAdvice.class);
			if (modelSize == 0 && binderSize == 0 && reqCount == 0 && resCount == 0) {
				logger.debug("ControllerAdvice beans: none");
			}
			else {
				logger.debug("ControllerAdvice beans: " + modelSize + " @ModelAttribute, " + binderSize +
						" @InitBinder, " + reqCount + " RequestBodyAdvice, " + resCount + " ResponseBodyAdvice");
			}
		}
	}

List adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());

	/**在给定的{@link ApplicationContext}中找到带有{@link ControllerAdvice @ControllerAdvice}注释的bean
	 * Find beans annotated with {@link ControllerAdvice @ControllerAdvice} in the
	 * given {@link ApplicationContext} and wrap them as {@code ControllerAdviceBean}
	 * instances.并将它们包装为{@code ControllerAdviceBean}实例。
	 * <p>As of Spring Framework 5.2, the {@code ControllerAdviceBean} instances
	 * in the returned list are sorted using {@link OrderComparator#sort(List)}. ,<p>从Spring Framework 5.2开始,返回列表中的{@code ControllerAdviceBean}实例使用{@link OrderComparatorsort(list)}进行排序。
	 * @see #getOrder() 
	 * @see OrderComparator
	 * @see Ordered
	 */
	public static List<ControllerAdviceBean> findAnnotatedBeans(ApplicationContext context) {
		List<ControllerAdviceBean> adviceBeans = new ArrayList<>();
		for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context, Object.class)) {
			if (!ScopedProxyUtils.isScopedTarget(name)) {
				ControllerAdvice controllerAdvice = context.findAnnotationOnBean(name, ControllerAdvice.class);
				if (controllerAdvice != null) {
					// Use the @ControllerAdvice annotation found by findAnnotationOnBean()
					// in order to avoid a subsequent lookup of the same annotation.
					adviceBeans.add(new ControllerAdviceBean(name, context, controllerAdvice));
				}
			}
		}
		OrderComparator.sort(adviceBeans);
		return adviceBeans;
	}

该类在这里会被扫描识别类下的方法:

在这里插入图片描述
ControllerAdviceController该类会被识别到,结果如下:
在这里插入图片描述
和上面注解修饰的方法对应。

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

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

相关文章

在线答题系统怎么做?一文为您揭秘!

在线答题系统是一种利用网络技术实现的答题平台&#xff0c;具有高效、便捷、灵活等特点&#xff0c;被广泛应用于教育、培训、考试、竞赛等场景。以下是其详细介绍&#xff1a; 一、 基本功能&#xff1a; 题目录入&#xff1a;支持多种方式录入题目&#xff0c;如手动输入、…

Android15之解决:Dex checksum does not match for dex:services.jar问题(二百三十五)

简介&#xff1a; CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布&#xff1a;《Android系统多媒体进阶实战》&#x1f680; 优质专栏&#xff1a; Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a; 多媒体系统工程师系列【…

前端接收到的日期格式为 2021-12-07T16:44:53.298+00:00 怎么办?

在写项目的时候&#xff0c;给前端发送了一个 Date 类型的数据,发现格式不对&#xff1a; 可以通过在application 配置文件中进行如下配置&#xff1a; spring:jackson:date-format: yyyy-MM-dd HH:mm:sstime-zone: GMT8 前端在获取就发现格式正确

登高赏菊迎重阳,与家人共乐同度佳节。

在金风送爽的重阳佳节&#xff0c;让我们登高远望&#xff0c;与亲人共赏菊花&#xff0c;共享团圆时光。愿清风明月&#xff0c;带来幸福与好运&#xff0c;让我们心怀感恩&#xff0c;笑对人生&#xff0c;共度这个美好的重阳节日&#xff01;

中安未来 OCR:合同抽取的高效利器

在数字化办公的时代&#xff0c;高效处理文档成为了众多企业的迫切需求。中安未来 OCR 技术以其强大的功能脱颖而出。 中安未来的 OCR 技术能够准确识别各种文档中的文字信息&#xff0c;其中合同抽取功能尤为实用。对于企业来说&#xff0c;合同管理至关重要。传统的合同处理方…

如何设置 GitLab 密码过期时间?

GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署极狐GitLab。 学习极狐GitLab 的相关资料&#xff1a; 极狐GitLab 60天专业…

CLIP——多模态预训练模型介绍

CLIP: Contrastive Language-Image Pre-training CLIP: 对比语言-图像预训练 CLIP的是由 OpenAI 2021年在 Learning Transferable Visual Models From Natural Language Supervision【利用文本的监督信号训练一个迁移能力强的视觉模型】中提出的一种多模态预训练模型&#xff…

AI荣耀时刻!2024诺贝尔物理奖、化学奖双双归属AI界

全球科学界迎来了2024最为瞩目的时刻——诺贝尔奖揭晓&#xff01;当诺贝尔物理奖和化学奖这两大科学殿堂的最高荣誉同时聚焦在人工智能&#xff08;AI&#xff09;领域时&#xff0c;AI技术无疑再次被推向了神坛&#xff0c;成为全球瞩目的焦点&#xff01;这一历史性的时刻&a…

2024年【焊工(初级)】最新解析及焊工(初级)模拟试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 焊工&#xff08;初级&#xff09;最新解析根据新焊工&#xff08;初级&#xff09;考试大纲要求&#xff0c;安全生产模拟考试一点通将焊工&#xff08;初级&#xff09;模拟考试试题进行汇编&#xff0c;组成一套焊…

来势汹汹,Eva Gamaiun超现实版权画时隔一年连发两案再次维权

案件基本情况起诉时间&#xff1a;2024-9-23、2024-9-24案件号&#xff1a;2024-cv-08763、2024-cv-08804原告&#xff1a;Eva Gamaiun原告律所&#xff1a;keith起诉地&#xff1a;伊利诺伊州北部法院品牌介绍Eva Gamayun&#xff0c;1990年出生&#xff0c;是一位自学成才的混…

vue项目 子组件在打开时调用父组件传过来的props里的数据

1 分析: 父组件在加载时就会加载子组件,所以此时调不到数据, 我们可以利用父组件内子组件的ref属性,获取子组件的方法, 在父组件的触发方法中调用直接传值 例: 父组件: //父组件事件AttributesRelations(row){this.dialogForm rowthis.$refs.AttributesRelationsRef.Attribu…

华为 HCIP-Datacom H12-821 题库 (35)

&#x1f423;博客最下方微信公众号回复题库,领取题库和教学资源 &#x1f424;诚挚欢迎IT交流有兴趣的公众号回复交流群 &#x1f998;公众号会持续更新网络小知识&#x1f63c; 1.一个 Route-Policy 下可以有多个节点&#xff0c;设备在调用Route-Policy时按顺序开始匹配 …

【最新华为OD机试E卷-支持在线评测】智能成绩表(100分)多语言题解-(Python/C/JavaScript/Java/Cpp)

🍭 大家好这里是春秋招笔试突围 ,一枚热爱算法的程序员 💻 ACM金牌🏅️团队 | 大厂实习经历 | 多年算法竞赛经历 ✨ 本系列打算持续跟新华为OD-E/D卷的多语言AC题解 🧩 大部分包含 Python / C / Javascript / Java / Cpp 多语言代码 👏 感谢大家的订阅➕ 和 喜欢�…

如何才能使绩效管理和薪酬管理完美结合?

如何才能使绩效管理和薪酬管理完美结合&#xff1f; 企业内部管理中&#xff0c;绩效考核与薪酬设计是人力资源管理的两大核心支柱。薪酬设计不仅是工资分配的基石&#xff0c;更是激发员工潜能的关键工具&#xff1b;绩效考核则作为评估标尺&#xff0c;衡量如销售额、服务满…

temu自养号测评采购系统搭建技巧与技术要求

TEMU自养号测评采购系统的搭建是一个细致且需关注多个环节的过程&#xff0c;以下是一些关键的搭建技巧&#xff1a; 一、基础环境搭建 1. 硬件参数隔离&#xff1a; 2. 利用国外服务器在云端设立安全终端&#xff0c;确保每个账号拥有独立的硬件底层参数&#xff0c;如安全…

MySQL C/C++ 的 API

MySQL 提供了一个用于 C/C 的 API&#xff0c;称为 MySQL Connector/C。该 API 允许通过 C/C 程序与 MySQL 数据库进行交互。 函数名称参数返回值描述mysql_initMYSQL *mysqlMYSQL *初始化一个 MySQL 对象&#xff0c;用于连接 MySQL 服务器。mysql_real_connectMYSQL *mysql,…

视频里的声音怎么单独提取出来?简单又实用的10种提取声音方法!

视频里的声音怎么单独提取出来&#xff1f;在当今这个数字化飞速发展的时代&#xff0c;视频已经成为信息传播的中流砥柱&#xff0c;而音频元素则是这个过程中一个举足轻重的组成部分&#xff0c;音频不仅扮演着声音背景的角色&#xff0c;更通过多种形式如旁白解说、背景音乐…

设备树pinctrl子系统

1.pinctrl子系统 大多数 SOC 的 pin 都是支持复用的&#xff0c;比如 IMX6ULL 的 GPIO1_IO03 既可以作为普通的GPIO 使用&#xff0c;也可以作为 I2C1 的 SDA 等等。此外我们还需要配置 pin 的电气特性&#xff0c;比如上/下拉、速度、驱动能力等等。传统的配置 pin 的方式就是…

一个月学会Java 第9天 构造器与访问修饰符

Day9 构造器与访问修饰符 本来其实是想在Day8里面把这个构造器给讲掉的&#xff0c;但是发现篇幅有点长的&#xff0c;后面的内容也是稍微有一点点超纲了&#xff0c;所以就先把这个留着&#xff0c;现在再讲。 第一章 构造器 构造器&#xff0c;我们之前在讲类的时候其实是说过…

CANoe_调用C#控件的方法_DEMO方法演示

1、DEMO存放位置 D:\Users\Public\Documents\Vector\CANoe\Sample Configurations 11.0.96\CAN\MoreExamples\ActiveX_DotNET_Panels 每个人的电脑因为有区别存放位置不一样 2、控件制作--使用C#控件可以直接制作 3、控件代码 using System; using System.Collections; usi…