Spring技术内幕笔记(八)------对Bean Reference的解析

本文探讨了Spring中BeanDefinition的解析过程,特别是在populateBean()方法中如何通过BeanDefinitionValueResolver解析BeanDefinition。重点介绍了RuntimeBeanReference在处理未创建Bean时的作用,以及在集合类型的解析中如何递归调用resolveValueIfNecessary方法。最后,文章总结了依赖注入的递归过程,包括在BeanWrapper#setPropertyValues中的实现,展示了如何通过getBean方法层层完成Bean的创建和注入。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在上篇文章中我们了解到了如何设置Bean之间的依赖关系,以及如何将一个Bean设置到它所依赖的另一个bean的属性中,但是我们还忘了一步,就是对BeanDefinition进行解析,在Spring中是通过BeanDefinitionResolver来对BeanDefinition进行解析的。

在populateBean()会创建一个BeanDefinitionValueResolver对象,然后调用BeanDefinitionValueResolver#resolveValueNecessary方法来对BeanDefinition进行解析,根本上其实是对一个propertyValue进行解析。

/**
	 * Given a PropertyValue, return a value, resolving any references to other
	 * beans in the factory if necessary.
	 给定一个PropertyValue,返回一个值,如果有必要,解析对工厂中其他bean的任何引用
	 The value could be:
	 这个value可以是
	 * <li>A BeanDefinition, which leads to the creation of a corresponding
	 * new bean instance. Singleton flags and names of such "inner beans"
	 * are always ignored: Inner beans are anonymous prototypes.
BeanDefinition,它导致创建相应的新bean实例。 Singleton标志和这种“内部bean”的名称总是被忽略:内部bean是匿名原型。
	 * <li>A RuntimeBeanReference, which must be resolved.
	 一个RuntimeBeanReference,必须解析
	 * <li>A ManagedList. This is a special collection that may contain
	 * RuntimeBeanReferences or Collections that will need to be resolved.
	 一个managedList,这是一个特殊的集合,可能包含需要解析的RuntimeBeanReference或者Collections
	 * <li>A ManagedSet. May also contain RuntimeBeanReferences or
	 * Collections that will need to be resolved.
	 一个ManagedSet。也可能包含RunTimeBeanReference或需要解决的集合
	 一个ManagedSet,
	 * <li>A ManagedMap. In this case the value may be a RuntimeBeanReference
	 * or Collection that will need to be resolved.
	 一个ManagedMap.在这种情况下,该值可能是需要解析的RunTimeBeanReference或Collection
	 * <li>An ordinary object or {@code null}, in which case it's left alone.
	 一个普通的对象或{@Code null},在这种情况下,它是独立的。
	 * @param argName the name of the argument that the value is defined for
	 为其定义值的参数的名称
	 * @param value the value object to resolve
	 要解析值的对象
	 * @return the resolved object
	 已经解析完成的对象
	 */
	@Nullable
	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.
			我们必须检查每个值以查看它是否需要运行时引用,以及另一个要解析的bean
		if (value instanceof RuntimeBeanReference) {
		如果value是RuntimeBeanReference的实例,也就是说我们在定义的BeanDefinition的时候需要依赖其他bean,但是在解析阶段没有其他BeanFactory中并没有我们所需要的bean,所以需要将这个被依赖的bean表示成RuntimeBeanReference对象,在创建bean的时候将依赖解析成真正的Spring中存在的bean
			RuntimeBeanReference ref = (RuntimeBeanReference) value;
			return resolveReference(argName, ref);
		}
		else if (value instanceof RuntimeBeanNameReference) {
		value是RuntimeBeanNameReference的实例,不可变占位符,用于属性值对象,当它是对工厂中另一个bean名称的引用时,在运行时解析
			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) {
		包含带有名称和别名的BeanDefinition
			// 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,不包含名称:使用虚拟名称
			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 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);
		}
		else if (value instanceof ManagedList) {
			// May need to resolve contained runtime references.
			可能需要解析运行时引用
			return resolveManagedList(argName, (List<?>) value);
		}
		else if (value instanceof ManagedSet) {
			// May need to resolve contained runtime references.
			同上,set类型
			return resolveManagedSet(argName, (Set<?>) value);
		}
		else if (value instanceof ManagedMap) {
			// May need to resolve contained runtime references.
			同上map类型
			return resolveManagedMap(argName, (Map<?, ?>) value);
		}
		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.
			将value转换成目标类型
			TypedStringValue typedStringValue = (TypedStringValue) value;
			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);
		}
	}

上面这个方法就是对BeanDefinition中的PropertyValu进行解析,由于我们在解析的过程中所依赖的bean都没有进行创建,所以需要使用RuntimeBeanReference对象,值得注意的一点的是,在对集合类型进行解析的过程中,采用递归的方式重新调用resolveValueIfNecessary方法,因为在集合中的元素也需要进行解析。

在所有的属性都已经解析完成之后,我们就已经为依赖注入准备好了条件,这是真正把bean对象设置到它所依赖的另一个bean的属性中去的地方,其处理的属性是各种各样的。具体的依赖注入发生在BeanWrapper#setPropertyValues中实现,完成在BeanWrapperImpl中实现

总结:

在Bean的创建和对象的依赖注入的过程中,需要依据BeanDefinition中的信息来递归的完成依赖注入,在这个过程中我们可以发现有两个递归过程,这两个递归过程都是以getBean为入口的,有一个递归是在上下文体系中查找需要的Bean和创建Bean的递归调用,另一个是在依赖注入的过程中,通过递归调用容器的getBean的方法,得到当前Bean的依赖Bean,同时也触发对依赖Bean的创建和注入。同时在对Bean属性进行依赖注入的过程其实也是一个递归的过程。这样我们就可以一层一层的完成Bean的创建和注入了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值