Spring 源码(16)Spring Bean的创建过程(7)属性填充

知识回顾

上一篇介绍了Spring中三级缓存singletonObjectsearlySingletonObjectssingletonFactoriesSpring在处理循环依赖时在实例化后属性填充前将一个lambda表达式放在了三级缓存中,后续在获取时进行了判断,如果不需要进行对象代理,那么直接返回对象Bean,然后将三级缓存中的对象删除,然后放在二级缓存中,后面在初始化之后又将二级缓存中的对象放在了一级缓存中,然后删除了二级缓存中的对象。

然后介绍了Spring在进行代理对象的创建时,会使用SmartInstantiationBeanPostProcessor接口的getEarlyBeanReference方法进行创建,创建的时候会调用到AbstractAutoProxyCreator类的实现,最终以JDK或者CGLIB的方式进行代理的创建,当然这些细节讲的不是很清晰,只是梳理了大致脉络,后续还会进行较为详细的梳理,敬请期待。

接下来继续主流程的解析,Bean的属性填充。

对象的属性填充

一般来说属性填充,可能会涉及到很多东西,比如填充的属性是基本类型还是引用类型,填充的方式又可以分为按类型、按名称还是其他的,然后填充时值的类型是否需要进行类型转换等。

属性填充:

Spring 源码(16)Spring Bean的创建过程(7)属性填充

属性填充大致可以分为对基本类型的数据进行填充和对应用类型的数据填充,populateBean方法中代码比较繁琐,会设计到很多的递归调用,最终解析并填充属性。

Spring中,实际上属性填充大致可以分为四步:

Spring 源码(16)Spring Bean的创建过程(7)属性填充

  • 使用InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation接口的调用,可以给机会在属性填充前对Bean进行修改,并且可以定制字段的填充
  • 按照注入方式进行属性的填充,最终会将解析到的属性和引用放入PropertyValues
    • 按类型进行自动注入
    • 按名称进行自动注入
  • 如果存在InstantiationAwareBeanPostProcessor接口,那么循环去调用postProcessProperties这个方法进行注解的注入,这里调用的实际上就是前面进行Bean的合并时解析的注解,比如:@Autowired@Resource@Value
  • 属性值的处理和解析
    • 创建一个BeanDefinitionValueResolver 值解析器
    • 循环去遍历解析属性值,解析过程中会用到类型转换的转换服务ConversionServiceSPEL表达式的解析、属性编辑器PropertyEditor
    • 最终解析完,会调用到属性的set方法进行写入

这里贴一下属性值解析的时候的源码:

public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
		// We must check each value to see whether it requires a runtime reference
		// to another bean to be resolved.
		// 根据值对象的类型进行解析
		if (value instanceof RuntimeBeanReference) {
			// 运行时引用
			RuntimeBeanReference ref = (RuntimeBeanReference) value;
			return resolveReference(argName, ref);
		}
		else if (value instanceof RuntimeBeanNameReference) {
			String refName = ((RuntimeBeanNameReference) value).getBeanName();
			refName = String.valueOf(doEvaluate(refName));
			if (!this.beanFactory.containsBean(refName)) {
				throw new BeanDefinitionStoreException(
						"Invalid bean name '" + refName + "' in bean reference for " + argName);
			}
			return refName;
		}
		else if (value instanceof BeanDefinitionHolder) {
			// Resolve BeanDefinitionHolder: contains BeanDefinition with name and aliases.
			BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value;
			return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());
		}
		else if (value instanceof BeanDefinition) {
			// Resolve plain BeanDefinition, without contained name: use dummy name.
			BeanDefinition bd = (BeanDefinition) value;
			String innerBeanName = "(inner bean)" + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR +
					ObjectUtils.getIdentityHexString(bd);
			return resolveInnerBean(argName, innerBeanName, bd);
		}
		else if (value instanceof DependencyDescriptor) {
			Set autowiredBeanNames = new LinkedHashSet(4);
			Object result = this.beanFactory.resolveDependency(
					(DependencyDescriptor) value, this.beanName, autowiredBeanNames, this.typeConverter);
			for (String autowiredBeanName : autowiredBeanNames) {
				if (this.beanFactory.containsBean(autowiredBeanName)) {
					this.beanFactory.registerDependentBean(autowiredBeanName, this.beanName);
				}
			}
			return result;
		}
		// 如果值是数组
		else if (value instanceof ManagedArray) {
			// May need to resolve contained runtime references.
			ManagedArray array = (ManagedArray) value;
			Class> elementType = array.resolvedElementType;
			if (elementType == null) {
				String elementTypeName = array.getElementTypeName();
				if (StringUtils.hasText(elementTypeName)) {
					try {
						elementType = ClassUtils.forName(elementTypeName, this.beanFactory.getBeanClassLoader());
						array.resolvedElementType = elementType;
					}
					catch (Throwable ex) {
						// Improve the message by showing the context.
						throw new BeanCreationException(
								this.beanDefinition.getResourceDescription(), this.beanName,
								"Error resolving array type for " + argName, ex);
					}
				}
				else {
					elementType = Object.class;
				}
			}
			return resolveManagedArray(argName, (List>) value, elementType);
		}
		// 如果值是list
		else if (value instanceof ManagedList) {
			// May need to resolve contained runtime references.
			return resolveManagedList(argName, (List>) value);
		}
		// 如果值是set
		else if (value instanceof ManagedSet) {
			// May need to resolve contained runtime references.
			return resolveManagedSet(argName, (Set>) value);
		}
		// 如果值是map
		else if (value instanceof ManagedMap) {
			// May need to resolve contained runtime references.
			return resolveManagedMap(argName, (Map, ?>) value);
		}
		// 如果值是properties
		else if (value instanceof ManagedProperties) {
			Properties original = (Properties) value;
			Properties copy = new Properties();
			original.forEach((propKey, propValue) -> {
				if (propKey instanceof TypedStringValue) {
					propKey = evaluate((TypedStringValue) propKey);
				}
				if (propValue instanceof TypedStringValue) {
					propValue = evaluate((TypedStringValue) propValue);
				}
				if (propKey == null || propValue == null) {
					throw new BeanCreationException(
							this.beanDefinition.getResourceDescription(), this.beanName,
							"Error converting Properties key/value pair for " + argName + ": resolved to null");
				}
				copy.put(propKey, propValue);
			});
			return copy;
		}
		// 如果值是字符串
		else if (value instanceof TypedStringValue) {
			// Convert value to target type here.
			TypedStringValue typedStringValue = (TypedStringValue) value;
			// 校验值,比如说使用spel表达式进行解析,然后得到这个值
			Object valueObject = evaluate(typedStringValue);
			try {
				Class> resolvedTargetType = resolveTargetType(typedStringValue);
				if (resolvedTargetType != null) {
					// 类型转换
					return this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType);
				}
				else {
					return valueObject;
				}
			}
			catch (Throwable ex) {
				// Improve the message by showing the context.
				throw new BeanCreationException(
						this.beanDefinition.getResourceDescription(), this.beanName,
						"Error converting typed String value for " + argName, ex);
			}
		}
		else if (value instanceof NullBean) {
			return null;
		}
		else {
			return evaluate(value);
		}
	}

代码比较长,大致的话就是对属性进行分类处理,比如引用类型的,ListMapSetProperties、数组、String类型的等。

如果在填充的过程中,发现需要的Bean不存在,那么又会进行getBeandoGetBeancreateBeandoCreateBean的调用,然后递归的入栈出栈调用,最终完成属性的填充。

下篇继续主流程中的Bean的初始化initializeBean调用的解读。

发布者:糖太宗,转载请注明出处:https://www.qztxs.com/archives/science/technology/8277

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022年5月22日 下午4:06
下一篇 2022年5月22日 下午4:21

相关推荐

  • 开源蜜罐使用心得1 - HFish插件 - 任意站点,皆可蜜罐

    HFish 插件是什么? 通过插件可以 100% 的让任意 WEB 服务成为蜜罐 HFish 插件是基于 Nginx + Lua 进行实现的 任意站点,皆可蜜罐 的牛逼思路! 目前已经打包好了 Docker 镜像,通过 hfishs/hub 可以快速让任意站点当成自己蜜罐。   有哪些使用场景? 只提供三种使用场景,更多场景自行思考 搭建开源 CM...

    技术 2022年6月13日
    5700
  • 缓存与数据库不一致,你遇到过吗?

    相信大家偶尔会遇到缓存与数据库不一致的问题。今天聊聊这个话题。   数据库主从,为什么会不一致? 先回顾下,无缓存时,数据库主从不一致问题。 如上图,发生的场景是,写后立刻读: (1)主库一个写请求(主从没同步完成); (2)从库接着一个读请求,读到了旧数据; (3)最后,主从同步完成;   导致的结果是:主动同步完成之前,会读取到旧数据。   可以看到,主...

    2022年5月10日
    1500
  • Windows日志事件ID说明

    日志路径:C:WindowsSystem32winevtLogs查看日志:Security.evtx、System.evtx、Application.evtx如何查看:右键我的电脑-管理-系统工具-事件查看器,或者eventvwr查看事件查看器 打开Windows系统的事件查看器,右键单击系统或安全日志,选择筛选当前日志,在筛选器中输入下列事件ID即可。 &...

    技术 2022年6月13日
    22400
  • 我们从来都反对“大中台,小前台”的架构设计!

    在2020全球敏捷架构峰会上,快狗打车的架构师李洪英,分享了快狗打车业务中台的一些经验与思考。 画外音:PPT见文末。   问题一:什么是平台? 定义:一种基于外部供应商和顾客之间的价值创造互动的商业模式;它是规则和标准的制定者。   问题二:平台分为哪几类? (1)应用平台; (2)业务平台; (3)技术平台;   问题三:平台的价值在哪里? 于他:为所有...

    2022年5月15日
    2300
  • 为什么说,MQ,是互联网架构的解耦神器?

    什么是耦合? 耦合,是架构中,本来不相干的代码、模块、服务、系统因为某些原因联系在一起,各自独立性差,影响则相互影响,变动则相互变动的一种架构状态。 感官上,怎么发现系统中的耦合? 作为技术人,每每在心中骂上下游,骂兄弟部门,“这个东西跟我有什么关系?为什么需要我来配合做这个事情?”。明明不应该联动,却要被动配合,就可能有潜在的耦合。   今天一起来看一个,...

    2022年5月7日
    4100

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信