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

1.在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;
				}
			}
		}

2.关键方法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;
	}

2.1 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();
				}
			}
		}

resolveMethodArguments方法:

	@Nullable
		private Object[] resolveMethodArguments(Method method, Object bean, @Nullable String beanName) {
			int argumentCount = method.getParameterCount();
			Object[] arguments = new Object[argumentCount];
			DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];
			Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount);
			Assert.state(beanFactory != null, "No BeanFactory available");
			TypeConverter typeConverter = beanFactory.getTypeConverter();

			// 遍历每个方法参数,找到匹配的bean对象
			for (int i = 0; i < arguments.length; i++) {
				MethodParameter methodParam = new MethodParameter(method, i);

				DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);
				currDesc.setContainingClass(bean.getClass());
				descriptors[i] = currDesc;
				try {
					Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);
					if (arg == null && !this.required) {
						arguments = null;
						break;
					}
					arguments[i] = arg;
				}
				catch (BeansException ex) {
					throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);
				}
			}
			synchronized (this) {
				if (!this.cached) {
					if (arguments != null) {
						DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length);
						registerDependentBeans(beanName, autowiredBeans);
						if (autowiredBeans.size() == argumentCount) {
							Iterator<String> it = autowiredBeans.iterator();
							Class<?>[] paramTypes = method.getParameterTypes();
							for (int i = 0; i < paramTypes.length; i++) {
								String autowiredBeanName = it.next();
								if (beanFactory.containsBean(autowiredBeanName) &&
										beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {
									cachedMethodArguments[i] = new ShortcutDependencyDescriptor(
											descriptors[i], autowiredBeanName, paramTypes[i]);
								}
							}
						}
						this.cachedMethodArguments = cachedMethodArguments;
					}
					else {
						this.cachedMethodArguments = null;
					}
					this.cached = true;
				}
			}
			return arguments;
		}

字段注入

  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. 利用反射将找到的所有结果对象传给当前方法,并执行。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

现在闪侠惠递寄快递有福利了,千万不要因没把握住而后悔呀!

闪侠惠递平台寄快递现在真的是太便宜了&#xff0c;优惠价格把握不住&#xff0c;后悔都来不及&#xff01;大家可以在闪侠惠递上面寄快递&#xff0c;价格真的非常优惠呢&#xff0c;比咱们平常寄快递的价格都优惠呢&#xff0c;真的&#xff0c;小编都亲自替大家尝试过了呢。…

联软安渡 UniNXG 安全数据交换系统 任意文件读取漏洞复现

0x01 产品简介 联软安渡UniNXG安全数据交换系统,是联软科技自研的业内融合网闸、网盘和DLP的一体机产品,它同时支持多网交换,查杀毒、审计审批、敏感内容识别等功能,是解决用户网络隔离、网间及网内数据传输、交换、共享/分享、存储的理想安全设备,具有开创性意义。 UniN…

千层烤馍,五彩斑斓的甘肃特色美食

甘肃玫瑰千层烤馍是一道具有浓郁地方特色的传统面点&#xff0c;以其独特的口感和精美的外观而闻名。食家巷的千层烤馍更是其中的佼佼者&#xff0c;它采用了优质的原料和传统的制作工艺&#xff0c;让你品尝到最正宗的甘肃味道。 食家巷千层烤馍的制作过程非常讲究&#xff0c…

CVHub | CVPR 2024 | 英伟达发布新一代视觉基础模型: AM-RADIO = CLIP + DINOv2 + SAM

本文来源公众号“CVHub”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;CVPR 2024 | 英伟达发布新一代视觉基础模型: AM-RADIO CLIP DINOv2 SAM 标题&#xff1a;《AM-RADIO: Agglomerative Vision Foundation Model Reduce Al…

GPT-4o,AI实时视频通话丝滑如人类,Plus功能免费可用

不开玩笑&#xff0c;电影《她》真的来了。 OpenAI最新旗舰大模型GPT-4o&#xff0c;不仅免费可用&#xff0c;能力更是横跨听、看、说&#xff0c;丝滑流畅毫无延迟&#xff0c;就像在打一个视频电话。 现场直播的效果更是炸裂&#xff1a; 它能感受到你的呼吸节奏&#xf…

爆款预警!2024年必火的五大软件应用,你准备好了吗?

2024年必火的五大软件应用可以从多个角度进行预测。首先&#xff0c;人工智能&#xff08;AI&#xff09;的应用将继续扩大其在软件开发和用户体验改善中的作用。AI技术被用于改善用户体验&#xff0c;如聊天机器人&#xff0c;创建数据驱动的战略和决策&#xff0c;预测趋势以…

学习神经网络基础架构

今日学习了解了常见的几种神经网络基础架构。 1.卷积神经网络 卷积神经网络CNN是一种人工神经网络&#xff0c;旨在处理和分析具有网格状拓扑结构的数据&#xff0c;如图像和视频。将 CNN 想象成一个多层过滤器&#xff0c;可处理图像以提取有意义的特征并进行推理预测。 想…

第十五节:贪心算法(下)

一 、 贪心算法的解题套路实战一&#xff08;最多的会议宣讲场次&#xff09; 1.1 描述 一些项目要占用一个会议室宣讲&#xff0c;会议室不能同时容纳两个项目的宣讲。 给你每一个项目开始的时间和结束的时间 你来安排宣讲的日程&#xff0c;要求会议室进行的宣讲的场次最多。…

Android 几种系统升级方式详解

目录 ◆ 概述 ● 几种启动模式 ● MISC分区 ● CACHE分区 ● 几种系统升级方式 ◆ Recovery升级 ● 升级包构成&#xff0c;签名&#xff0c;制作 ● 升级脚本 ● 升级过程 ◆ OTA升级 ● 升级包构成&#xff0c;制作 ● 升级脚本 ● 升级过程 ◆ fastboot升级 ◆ ADB升级 几…

System V IPC(进程间通信)机制详解

文章目录 一、引言二、System V IPC的基本概念1、IPC结构的引入2、IPC标识符&#xff08;IPC ID&#xff09;3、S ystem V的优缺点 三、共享内存&#xff08;Shared Memory&#xff09;1、共享内存的基本概念2、共享内存的创建&#xff08;shmget&#xff09;3、共享内存的附加…

FreeRTOS【4】线程挂起和恢复

1.开发背景 基于上一篇指引&#xff0c;成功创建并启动线程后&#xff0c;线程已经开始运行了&#xff0c;但是有时我们需要线程暂停运行&#xff0c;例如某个线程是控制 LED 闪灯的&#xff0c;如果现在需要让 LED 停止工作&#xff0c;单纯的关闭 LED 是没用的&#xff0c;因…

刷题之最长连续序列

哈希表 class Solution { public:int longestConsecutive(vector<int>& nums) {//set记录并且去重nums中的数unordered_set<int>set;for(int i0;i<nums.size();i){set.insert(nums[i]);}int result0;//遍历所有数for(auto iset.begin();i!set.end();i){//如…

智能EDM邮件群发工具哪个好?

企业之间的竞争日益激烈&#xff0c;如何高效、精准地触达目标客户&#xff0c;成为每个市场战略家必须面对的挑战。在此背景下&#xff0c;云衔科技凭借其前沿的AI技术和深厚的行业洞察&#xff0c;匠心推出了全方位一站式智能EDM邮件营销服务平台&#xff0c;重新定义了邮件营…

(三)Spring教程——依赖注入与控制反转

Spring框架是为了简化企业级应用开发而创建的&#xff0c;其强大之处在于对Java SE和Java EE开发进行全方位的简化&#xff0c;Spring还对常用的功能进行封装&#xff0c;可以极大地提高Java EE的开发效率。 依赖注入是Spring的核心技术之一&#xff0c;也被称为“控制反转”&a…

Element-UI 快速入门指南

文章目录 一、安装 Element-UI1.1 使用 npm 安装1.2 使用 yarn 安装 二、引入 Element-UI三、使用 Element-UI 组件3.1 按钮组件3.2 输入框组件3.3 表单组件3.4 表格组件3.5 弹框组件 四、自定义主题4.1 安装主题工具4.2 初始化变量文件4.3 编译主题 五、总结 &#x1f389;欢迎…

栈:概念与实现,超简单!!!

1.概念 压栈&#xff1a;栈的插入操作叫做进栈/压栈/入栈&#xff0c;入数据在栈顶。出栈&#xff1a;栈的删除操作叫做出栈&#xff0c;出数据也在栈顶。栈的元素遵循后进先出LIFO(Last In First Out)的原则。后面进来的数据先出去 2.栈的实现 三种实现方法&#xff0c;数组…

如何在Springboot项目的Mapper中增加一个新的sql语句

在做项目的过程中&#xff0c;我发现有的时候需要用到一些不在springboot的Mapper中的Sql语句&#xff0c;那么应该如何进行操作呐&#xff1f;&#xff1f; 平常我们创建springbootmybatisPlus项目的时候是这样创建的&#xff1a;&#xff1a; 1、创建实体类 2、创建Mappe…

四川景源畅信:抖音有哪些可以做的副业?

抖音作为当前最受欢迎的短视频平台之一&#xff0c;其巨大的流量和用户基础为许多人提供了副业的机会。那么&#xff0c;在抖音上可以做哪些副业呢? 一、内容创作与推广 利用抖音平台进行内容创作是最直接的副业方式。无论是搞笑短剧、生活分享还是专业知识普及&#xff0c;只…

深入了解 npm 命令

文章目录 安装 npm初始化项目安装包更新包卸载包查看已安装的包查找包其他常用命令结论 在现代 JavaScript 开发中&#xff0c;npm&#xff08;Node Package Manager&#xff09;是一个不可或缺的工具。它是 Node.js 生态系统的一部分&#xff0c;用于管理 JavaScript 包和依赖…