Autowired注解源码解析

news2025/6/2 0:28:32

一、Autowired注解的原理的概览

我们都知道一个Bean的大致生命周期有这几个阶段,实例化--> 属性填充 --> 初始化  --> 销毁回调

 其中Autowired作用的时间就是在属性填充阶段,而且是通过AutowiredAnnotation BeanPostProcessor类进行处理的。注入的整体流程如下:

 二、一步步分析Autowired的源码

AutowiredAnnotationBeanPostProcessor的postProcessProperties方法是我们此次分析的入口。其代码如下:

	@Override
	public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
		InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
		try {
			metadata.inject(bean, beanName, pvs);
		}
		catch (BeanCreationException ex) {
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
		}
		return pvs;
	}

 除了异常处理外,这里主要调用两个方法findAutowiringMetadata(用来查找标注有autowried注解的字段和方法)、metadata.inject(基于已经找到需要注入的信息来去spring容器中获取到对应的bean进行注入)。下面将重点分析这两个方法

1、findAutowiringMetadata方法详解

	private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
		// Fall back to class name as cache key, for backwards compatibility with custom callers.
		String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
		// Quick check on the concurrent map first, with minimal locking.
		// 首先从缓存中获取当前需要进行注入的元数据,缓存的key为bean的名称(如果有),否则为类名
		InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
		// 判断是否刷新的条件是:1、metadata为null , 2、要注入的目标类跟当前入参中的clazz不是同一个类型
		if (InjectionMetadata.needsRefresh(metadata, clazz)) {
			// 这里使用双重检查机制保证没有二次去出发构建自动注入的方法
			synchronized (this.injectionMetadataCache) {
				metadata = this.injectionMetadataCache.get(cacheKey);
				if (InjectionMetadata.needsRefresh(metadata, clazz)) {
					if (metadata != null) {
						metadata.clear(pvs);
					}
					// 构建需要自动的元数据类
					metadata = buildAutowiringMetadata(clazz);
					this.injectionMetadataCache.put(cacheKey, metadata);
				}
			}
		}
		return metadata;
	}

上面的方法中我们优先从缓存中去获取自动注入的对象,如果缓存中有说明之前已经创建过了,直接进行返回,没有的化执行创建动作。接下来我们重点关注buildAutowiringMetadata方法

1.1 buildAutowiringMetadata方法解析

	private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
		if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
			return InjectionMetadata.EMPTY;
		}

		List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
		Class<?> targetClass = clazz;

		do {
			final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
			
			//  1、查找所有的标注了@Autowired的字段,生成AutowiredFieldElement对象,添加到currElements集合
			ReflectionUtils.doWithLocalFields(targetClass, field -> {
				MergedAnnotation<?> ann = findAutowiredAnnotation(field);
				if (ann != null) {
					if (Modifier.isStatic(field.getModifiers())) {
						if (logger.isInfoEnabled()) {
							logger.info("Autowired annotation is not supported on static fields: " + field);
						}
						return;
					}
					boolean required = determineRequiredStatus(ann);
					currElements.add(new AutowiredFieldElement(field, required));
				}
			});
			//  2、查找所有的标注了@Autowired的方法,生成AAutowiredMethodElement对象,添加到currElements集合
			ReflectionUtils.doWithLocalMethods(targetClass, method -> {
				Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
				if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
					return;
				}
				MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
				if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
					if (Modifier.isStatic(method.getModifiers())) {
						if (logger.isInfoEnabled()) {
							logger.info("Autowired annotation is not supported on static methods: " + method);
						}
						return;
					}
					if (method.getParameterCount() == 0) {
						if (logger.isInfoEnabled()) {
							logger.info("Autowired annotation should only be used on methods with parameters: " +
									method);
						}
					}
					boolean required = determineRequiredStatus(ann);
					PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
					currElements.add(new AutowiredMethodElement(method, required, pd));
				}
			});

			elements.addAll(0, currElements);
			targetClass = targetClass.getSuperclass();
		}
		// 3、向上递归父类,知道找到Object为止
		while (targetClass != null && targetClass != Object.class);
		// 4、 基于之前创建的AutowiredElements生成InjectionMetadata实例
		return InjectionMetadata.forElements(elements, clazz);
	}

该方法中主要做了三件事,

1、查找所有的标注了@Autowired的字段,生成AutowiredFieldElement对象,添加到currElements集合

2、查找所有的标注了@Autowired的方法,生成AAutowiredMethodElement对象,添加到currElements集合


3、 基于前两步创建的AutowiredElements生成InjectionMetadata实例

至此我们已经生成了InjectionMetadata对象,

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

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

相关文章

android14预览版介绍及解读

​ 前言&#xff1a; android14快要来了&#xff0c;最近2月8日&#xff0c;android14的第一个开发者预览版发布了&#xff0c;正式版大约会和往常一样&#xff0c;大概率在六月份左右推出&#xff0c;八九月份时会有国内会有第一批手机支持安卓14。所以&#xff0c;本文就带…

为什么要用频谱分析仪测量频谱?

频谱分析仪是研究电信号频谱结构的仪器&#xff0c;用于信号失真度、调制度、谱纯度、频率稳定度和交调失真等信号参数的测量&#xff0c;可用以测量放大器和滤波器等电路系统的某些参数&#xff0c;是一种多用途的电子测量仪器。从事通信工程的技术人员&#xff0c;在很多时候…

免费下载学术文献的网站,好用!

推荐几款好用的免费下载学术文献网站&#xff0c;让你的查找文献环节更加事半功倍&#xff01; 1、Open Access Library&#xff08;OALib&#xff09;图书馆让学者可以免费下载学术文献和论文&#xff0c;并在这个平台上发表自己的论文。提供Open Access数据库资源。 2、文献…

Spring Security实现RBAC权限模型练习

1.Spring Security介绍 Spring Security的核心功能就是认证、授权、攻击防护&#xff0c;Spring Boot项目启动之后会自动进行配置&#xff0c;其核心就是一组链式过滤器。 如下图所示&#xff0c;对于一个用户请求&#xff0c;Username Password Authentication Filter验证用…

2022年API安全研究报告

导读 API应用的增速与其安全发展的不平衡,使其成为恶意攻击的首选目标,围绕API安全的攻防较量愈演愈烈。 2022年API安全风险概况 2022年平均每月遭受攻击的API数量超21万 2022年全年平均每月遭受攻击的API数量超过21万,第二季度(4-6月)遭受攻击的API数量达到高峰,月均…

经典文献阅读之--IGP2(可解释性目标的自动驾驶预测与规划)

0. 简介 对于自动驾驶的预测和规划而言&#xff0c;能够有效的对目标产生可解释性是非常有必要的&#xff0c;而《Interpretable Goal-based Prediction and Planning for Autonomous Driving》文中就提出了一种综合的自动驾驶预测和规划系统&#xff0c;它利用合理的逆规划来…

php mysql娱乐场所运营管理系统

目 录 1 背景与意义 3 1.1 研究背景 3 1.2 国内外发展状况研究 3 2 系统开发环境与技术 4 2.1 PHP介绍 4 2.2 MYSQL介绍 5 2.3 APACHE介绍 6 2.4 dreameaver介绍 7 2.5 wamp介绍 7 3 系统分析 8 3.1 系统可行性分析 8 3.1.1 技术可行性 …

【编程基础之Python】1、初始Python

【编程基础之Python】1、初始Python初始Python什么是PythonPython的运行过程Python的应用领域如何学好Python初始Python Python是一种跨平台的、开源免费的、解释型的、面向对象的高级编程语言。 Python的应用领域非常广泛&#xff0c;包括客户端程序、服务器程序、移动端程序…

Redis未授权漏洞蜜罐模拟与捕获分析

1.概述 文章主要分析Redis未授权漏洞的原理及形成原因&#xff0c;使用vulhub靶场进行漏洞复现&#xff0c;在了解漏洞原理并复现的基础上使用golang编写蜜罐代码进行模拟&#xff0c;开放端口在网上捕获真实存在的恶意攻击行为&#xff0c;对恶意样本进行分析&#xff0c;总结…

C++与Lua交互实例 -- 矩阵的加减乘除(版本二)

C与Lua交互实例 – 矩阵的加减乘除&#xff08;版本二&#xff09; TIPS&#xff1a;关于使用矩阵的加减乘除测试C与Lua的交互以及下面没讲述到的知识点可以阅读第一版&#xff1a; https://blog.csdn.net/qq135595696/article/details/128960951 同时下面两个方式矩阵的数据都…

爬虫JS逆向思路 - - 扣JS(data解密)

网络上几千块都学不到的JS逆向思路这里全都有&#x1f44f;&#x1f3fb;&#x1f44f;&#x1f3fb;&#x1f44f;&#x1f3fb; 本系列持续更新中&#xff0c;三连关注不迷路&#x1f44c;&#x1f3fb; 干货满满不看后悔&#x1f44d;&#x1f44d;&#x1f44d; ❌注意…

电机过流的一次bug排查记录

一、bug现象描述如下&#xff1a; 有一天&#xff0c;某员工给自己的组件换一个语音模块&#xff0c;其中电机和主板是通过单总线连接&#xff0c;据该员工回忆曾经在换语音芯片时曾将电源线不小心短路过。 电机已经DVT试产&#xff0c;功能和硬件测试已经通过&#xff0c;但是…

小白系列Vite-Vue3-TypeScript:007-配置axios并封装api

上一篇我们介绍了ViteVue3TypeScript项目中Element Plus的安装和配置&#xff0c;本篇我们来介绍一下如何配置axios并封装api。axios是一个基于promise的HTTP库&#xff0c;可以用在浏览器和node.js中&#xff0c;其最大的亮点就是支持了ES6里的Promise Api。废话不多说&#x…

Node =>Express学习

1.Express 能做什么 能快速构建web网站的服务器 或 Api接口的服务期 Web网站服务器&#xff0c;专门对外提供Web网页资源的服务器Api接口服务器&#xff1a;专门对外提供API接口的服务器 2.安装 在项目所处的目录中&#xff0c;运行以下命令&#xff0c;简装到项目中了 npm …

ChatGPT与马斯克 在 “ 遥感 ” 中的初探索

有人说&#xff1a;一个人从1岁活到80岁很平凡&#xff0c;但如果从80岁倒着活&#xff0c;那么一半以上的人都可能不凡。 生活没有捷径&#xff0c;我们踩过的坑都成为了生活的经验&#xff0c;这些经验越早知道&#xff0c;你要走的弯路就会越少。 1前言 文章开始前&#x…

栈和队列基本原理

栈和队列基本原理1.栈1.1 栈基本原理1.2. 栈操作步骤1.2.1 插入数据流程【压栈】1.2.2 移除数据流程【出栈】1.3. 栈代码实现2.队列2.1 队列基本原理2.2 队列操作步骤2.2.1 插入数据2.2.2 移除数据2.3. 队列代码实现3.栈与队列对比1.栈 1.1 栈基本原理 栈顶【末尾】&#xff…

突破边界:“超融合+”带来的商业化精益之路

相信大家都看了《流浪地球2》&#xff0c;其中人类一次次超越极限&#xff0c;以勇气和责任完成伟大征程的情节让我们深深感动。在现实的科技发展中&#xff0c;我们可能不会像科幻作品那样完成惊险万分地完成突破。但超越极限&#xff0c;却时时刻刻发生在科技产业当中。“超融…

K_A12_002 基于STM32等单片机采集光敏电阻传感器参数串口与OLED0.96双显示

K_A12_002 基于STM32等单片机采集光敏电阻传感器参数串口与OLED0.96双显示一、资源说明二、基本参数参数引脚说明三、驱动说明IIC地址/采集通道选择/时序对应程序:四、部分代码说明1、接线引脚定义1.1、STC89C52RC光敏电阻传感器模块1.2、STM32F103C8T6光敏电阻传感器模块五、基…

星河案例 | 冲量在线助力中国电信打造数据要素融通与AI能力开放外拓新范式

2022 年大数据“星河”案例征集活动由中国信息通信研究院、中国通信标准化协会大数据技术标准推进委员会(CCSA TC601)共同组织&#xff0c;旨在促进大数据技术产品及相关产业发展&#xff0c;加快培育数据要素市场、充分发挥数据作为生产要素的独特价值&#xff0c;树立行业标杆…

OnGUI Box 控件||Unity 3D OnGUI 常用控件

OnGUI Box 控件Unity 3D Box 控件用于在屏幕上绘制一个图形化的盒子。Box 控件中既可以显示文本内容&#xff0c;也可以绘制图片&#xff0c;或两者同时存在。GUIContent 和 GUIStyle 对于 Box 控件同样适用&#xff0c;既可以用来修饰 Box 控件的文本颜色&#xff0c;也可以用…