我是靠谱客的博主 开心缘分,最近开发中收集的这篇文章主要介绍Spring 源码之Spring Bean的创建过程中的属性填充,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

知识回顾

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

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

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

对象的属性填充

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

属性填充:

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

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

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

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

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

最后

以上就是开心缘分为你收集整理的Spring 源码之Spring Bean的创建过程中的属性填充的全部内容,希望文章能够帮你解决Spring 源码之Spring Bean的创建过程中的属性填充所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(35)

评论列表共有 0 条评论

立即
投稿
返回
顶部