java-spring 09 下.populateBean (方法成员变量的注入@Autowird,@Resource)

news2024/9/29 7:32:49

01.在populateBean 方法中的:用于@Autowird,@Resource注入

	// 后处理器已经初始化
		boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
		// 需要依赖检查
		boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

		PropertyDescriptor[] filteredPds = null;
		if (hasInstAwareBpps) {
			if (pvs == null) {
				pvs = mbd.getPropertyValues();
			}
			// 3. 成员变量的注入
			// 调用了InstantiationAwareBeanPostProcessor.postProcessProperties 方法 和 postProcessPropertyValues 方法 来进行设值后处理
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;					
					// 调用设值
					PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
					if (pvsToUse == null) {
						if (filteredPds == null) {
							filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
						}
						// 如果postProcessProperties 返回null,再调用 postProcessPropertyValues这个过时的方法
						pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
						if (pvsToUse == null) {
							return;
						}
					}
					pvs = pvsToUse;
				}
			}
		}

02.关键方法ibp.postProcessProperties方法:

Spring在AutowiredAnnotationBeanPostProcessor的postProcessProperties()方法中,会遍历所找到的注入点依次进行注入。


	@Override
	public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
		// 找注入点(所有被@Autowired注解了的Field或Method)
		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方法:

属性元数据封装到AutowiredFieldElement,方法元数据封装到AutowiredMethodElement,最后都封装到InjectionMetadata
`
 二者都是AutowiredAnnotationBeanPostProcessor的内部类,继承InjectionMetadata.InjectedElement

在这里插入图片描述
metadata.inject方法:

循环遍历属性、方法元数据进行注入;封装的对象都是继承InjectedElement的
·
 会先进行属性注入,再进行方法注入,所以属性注入会存在被覆盖的可能
·
 根据这个特性,可以对static修饰的对象,进行方法注入,达到属性注入的效果

	public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
		Collection<InjectedElement> checkedElements = this.checkedElements;
		Collection<InjectedElement> elementsToIterate =
				(checkedElements != null ? checkedElements : this.injectedElements);
		if (!elementsToIterate.isEmpty()) {
			// 遍历每个注入点进行依赖注入
			for (InjectedElement element : elementsToIterate) {
				element.inject(target, beanName, pvs);
			}
		}
	}

element.inject方法:
这个方法会在AutowiredFieldElement和AutowiredMethodElement重写

AutowiredFieldElement.inject

	@Override
		protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {

			Field field = (Field) this.member;
			Object value;
			if (this.cached) {
				// 对于原型Bean,第一次创建的时候,也找注入点,然后进行注入,此时cached为false,注入完了之后cached为true
				// 第二次创建的时候,先找注入点(此时会拿到缓存好的注入点),也就是AutowiredFieldElement对象,此时cache为true,也就进到此处了
				// 注入点内并没有缓存被注入的具体Bean对象,而是beanName,这样就能保证注入到不同的原型Bean对象
				try {
					value = resolvedCachedArgument(beanName, this.cachedFieldValue);
				}
				catch (NoSuchBeanDefinitionException ex) {
					// Unexpected removal of target bean for cached argument -> re-resolve
					value = resolveFieldValue(field, bean, beanName);
				}
			}
			else {
				// 根据filed从BeanFactory中查到的匹配的Bean对象
				value = resolveFieldValue(field, bean, beanName);
			}

			// 反射给filed赋值
			if (value != null) {
				ReflectionUtils.makeAccessible(field);
				field.set(bean, value);
			}
		}


resolveFieldValue方法:resolveDependency方法来获取依赖的属性bean

	@Nullable
		private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {

			DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
			desc.setContainingClass(bean.getClass());

			Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
			Assert.state(beanFactory != null, "No BeanFactory available");
			TypeConverter typeConverter = beanFactory.getTypeConverter();
			Object value;
			try {
				value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
			}
			catch (BeansException ex) {
				throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
			}
			synchronized (this) {
				if (!this.cached) {
					Object cachedFieldValue = null;
					if (value != null || this.required) {
						cachedFieldValue = desc;
						// 注册一下beanName依赖了autowiredBeanNames,
						registerDependentBeans(beanName, autowiredBeanNames);
						if (autowiredBeanNames.size() == 1) {
							String autowiredBeanName = autowiredBeanNames.iterator().next();
							if (beanFactory.containsBean(autowiredBeanName) &&
									beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
								// 构造一个ShortcutDependencyDescriptor作为缓存,保存了当前filed所匹配的autowiredBeanName,而不是对应的bean对象(考虑原型bean)
								cachedFieldValue = new ShortcutDependencyDescriptor(
										desc, autowiredBeanName, field.getType());
							}
						}
					}
					this.cachedFieldValue = cachedFieldValue;
					this.cached = true;
				}
			}
			return value;
		}
	}

AutowiredMethodElement.inject

	@Override
		protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
			// 如果pvs中已经有当前注入点的值了,则跳过注入
			if (checkPropertySkipping(pvs)) {
				return;
			}
			Method method = (Method) this.member;
			Object[] arguments;
			if (this.cached) {
				try {
					arguments = resolveCachedArguments(beanName);
				}
				catch (NoSuchBeanDefinitionException ex) {
					// Unexpected removal of target bean for cached argument -> re-resolve
					arguments = resolveMethodArguments(method, bean, beanName);
				}
			}
			else {
				arguments = resolveMethodArguments(method, bean, beanName);
			}
			if (arguments != null) {
				try {
					ReflectionUtils.makeAccessible(method);
					method.invoke(bean, arguments);
				}
				catch (InvocationTargetException ex) {
					throw ex.getTargetException();
				}
			}
		}

字段注入

  1. 遍历所有的AutowiredFieldElement对象。
  2. 将对应的字段封装为DependencyDescriptor对象。
  3. 调用BeanFactory的resolveDependency()方法,传入DependencyDescriptor对象,进行依赖查找,找到当前字段所匹配的Bean对象。
  4. 将DependencyDescriptor对象和所找到的结果对象beanName封装成一个ShortcutDependencyDescriptor对象作为缓存,比如如果当前Bean是原型Bean,那么下次再来创建该Bean时,就可以直接拿缓存的结果对象beanName去BeanFactory中去那bean对象了,不用再次进行查找了
  5. 利用反射将结果对象赋值给字段。

Set方法注入

  1. 遍历所有的AutowiredMethodElement对象
  2. 遍历将对应的方法的参数,将每个参数封装成MethodParameter对象
  3. 将MethodParameter对象封装为DependencyDescriptor对象
  4. 调用BeanFactory的resolveDependency()方法,传入DependencyDescriptor对象,进行依赖查找,找到当前方法参数所匹配的Bean对象。
  5. 将DependencyDescriptor对象和所找到的结果对象beanName封装成一个ShortcutDependencyDescriptor对象作为缓存,比如如果当前Bean是原型Bean,那么下次再来创建该Bean时,就可以直接拿缓存的结果对象beanName去BeanFactory中去那bean对象了,不用再次进行查找了
  6. 利用反射将找到的所有结果对象传给当前方法,并执行。

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

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

相关文章

基于FPGA的数字信号处理(11)--定点数的舍入模式(2)向最临近值取整nearest

前言 在之前的文章介绍了定点数为什么需要舍入和几种常见的舍入模式。今天我们再来看看另外一种舍入模式&#xff1a;向最临近值取整nearest。 10进制数的nearest nearest&#xff1a; 向最临近值方向取整。它的舍入方式和四舍五入非常类似&#xff0c;都是舍入到最近的整数…

【电路笔记】-无源高通滤波器

无源高通滤波器 文章目录 无源高通滤波器1、概述2、一阶高通滤波器的频率响应3、高通滤波器示例4、二阶高通滤波器5、RC 差异化因素高通滤波器与低通滤波器电路完全相反,因为这两个组件已互换,滤波器输出信号现在从电阻器两端获取。 1、概述 由于低通滤波器只允许低于其截止…

【论文合集1】- 存内计算加速机器学习

本章节论文合集&#xff0c;存内计算已经成为继冯.诺伊曼传统架构后&#xff0c;对机器学习推理加速的有效解决方案&#xff0c;四篇论文从存内计算用于机器学习&#xff0c;模拟存内计算&#xff0c;对CNN/Transformer架构加速角度阐述存内计算。 【1】WWW: What, When, Where…

C# OpenCvSharp Demo - 棋盘格相机标定

C# OpenCvSharp Demo - 棋盘格相机标定 目录 效果 项目 代码 下载 效果 项目 代码 using OpenCvSharp; using System; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.Drawing.Imaging; using System.Text; using Sys…

2019年计算机真题

2019年计算机真题 离散数学 一、用逻辑符号表达下列语句(论域为包含一切事物的集合) 1&#xff09;过平面上的两个点&#xff0c;有且仅有一条直线通过。 解: (1) P ( x , y ) : x , y \mathrm{P}_{(\mathrm{x}, \mathrm{y})}: \mathrm{x}, \mathrm{y} P(x,y)​:x,y 是平面上的…

线性表

1.1线性表的定义 线性表&#xff1a;零个或多个数据元素的有限序列。 注&#xff1a; &#xff08;1&#xff09;它是一个序列。元素之间是有顺序的&#xff0c;若元素存在多个&#xff0c;则第一个元素无前驱&#xff0c;最后一个元素无后继&#xff0c;其他元素有且只有一个…

SpringBoot 使用logback(多环境配置)

Logback是由log4j创始人设计的又一个开源日志组件。可用于项目日志功能。官网地址 第1步&#xff1a;添加坐标依赖 <!--logback--> <dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version…

该问题未得到解决(仅记录)

https://releases.ubuntu.com/bionic/进入网页下载ubuntu 选择烧录软件将下载的Ubuntu烧录到U盘中 之前用这个U盘烧录过一次&#xff0c;成功了&#xff0c;后来应该是U盘受损或者是什么其他原因使得用这个U盘总是烧录失败

网安面经之xss漏洞

目录 一、XSS漏洞 1、xss漏洞原理与危害 2、xss的类型&#xff1f;区别&#xff1f;修复&#xff1f; 3、常见使用的标签&#xff0c;payload构造 一、XSS漏洞 1、xss漏洞原理与危害 原理&#xff1a;xss就是跨站脚本攻击漏洞&#xff0c;也可以理解为前端的代码注入&…

数字人金融应用技术指南

根据《北京金融科技产业联盟团体标准管理办法》的规定&#xff0c;2024年3月27日经北京金融科技产业联盟第三届理事会第二次会议审议&#xff0c;批准发布《数字人金融应用技术指南》&#xff08;T/BFIA 027—2024&#xff09;、《图数据库金融应用技术要求》&#xff08;T/BFI…

医院转型新突破:精益六西格玛助力管理费大降13%,业务飙升26%

近年来&#xff0c;越来越多的医院开始尝试引入精益六西格玛管理模式&#xff0c;以期实现管理费的降低和业务量的增长。那么&#xff0c;精益六西格玛模式真的有这么牛吗&#xff1f;深圳天行健六西格玛培训公司将从实践角度出发&#xff0c;探讨精益六西格玛如何助力医院实现…

GAME101-Lecture06学习

前言 上节课主要讲的是三角形的光栅化。重要的思想是要利用像素的中心对三角形可见性的函数进行采样。 这节课主要就是反走样。 课程链接&#xff1a;Lecture 06 Rasterization 2 (Antialiasing and Z-Buffering)_哔哩哔哩_bilibili 反走样引入 ​ 通过采样&#xff0c;得到…

Vuex核心概念-state状态

目录 一、目标 二、提供数据 三、使用数据 1.通过store直接访问 2.通过辅助函数&#xff08;简化&#xff09; 一、目标 明确如何给仓库提供数据&#xff0c;如何使用仓库的数据 二、提供数据 State提供唯一的公共数据源&#xff0c;所有共享的数据都要统一放到Store中的…

了解 条码工具 Dynamsoft 在条码读取器中的形态运算

在图像处理中&#xff0c;术语形态学是指分析形状以填充小孔、去除噪声、提取轮廓等的一组操作。形态学操作很像空间卷积中的过滤过程。有两个部分在起作用&#xff1a;结构元素和预定义的计算规则。 点击下载Dynamsoft最新版https://www.evget.com/product/3691/download 结…

C#上位机1ms级高精度定时任务

precisiontimer 安装扩展包 添加引用 完整代码 using PrecisionTiming;using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; us…

Java数组(二)

Java数组&#xff08;二&#xff09; 1、多维数组 多维数组可以看成是数组的数组&#xff0c;比如二维数组就是一个特殊的一维数组&#xff0c;其每一个元素都是一个一维数组。二维数组 int a[][] new int[2][5];解析&#xff1a;以上二维数组a可以看成一个两行五列的数组。…

七、Redis三种高级数据结构-HyperLogLog

Redis HyperLogLog是用来做基数统计的算法&#xff0c;HyperLogLog在优点是&#xff0c;在输入的元素的数量或者体积非常大时&#xff0c;计算基数占用的空间总是固定的、并且非常小。在Redis里每个HyperLogLog键只需花费12KB内存&#xff0c;就可以计算接近 264 个元素的基数。…

政安晨【零基础玩转各类开源AI项目】:基于Ubuntu系统本地部署使用GPT-SoVITS进行语音克隆与TTS语音生成

目录 介绍 什么是TTS 安装Miniconda 框架功能 测试通过的环境 开始 1. 安装好miniconda 2. 进入下载的GPT-SoVITS目录 3. 创建虚拟环境并执行脚本 4. 执行过程中可能会出错 5. 下载预训练模型 6. 训练过程中可能会报错 7. 使用过程中可能出错 8.以下是使用全过程…

Java入门基础学习笔记8——注释

1、注释&#xff1a; 注释是写在程序中对代码进行解释说明的文件&#xff0c;方便自己和其他人查看&#xff0c;以便理解程序的。 package cn.ensource.note;/**文档注释文档注释 */ public class NoteDemo {public static void main(String[] args) {// 单行注释System.out.…

Vue从入门到实战Day04

一、组件的三大组成部分&#xff08;结构/样式/逻辑&#xff09; 1. scoped样式冲突 默认情况&#xff1a;写在组件中的样式会全局生效 -> 因此很容易造成多个组件之间的样式冲突问题。 1. 全局样式&#xff1a;默认组件中的样式会作用到全局 2. 局部样式&#xff1a;可以…