前言
从上一篇文章中得知,在BeanDefinitionValueResolver类的resolveValueIfNecessary方法中,可以解析并且转换参数值的类型。
那么,它到底是怎么做的呢?
1 resolveValueIfNecessary方法
下面重点看看BeanDefinitionValueResolver类的resolveValueIfNecessary方法是如何转换参数值的。
public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
//如果属性值是bean的引用类型
//<property name="user1" ref="user"/>
if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference) value;
//解析相关引用
return resolveReference(argName, ref);
}
//如果属性值是bean名称的引用类型
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;
}
//如果属性值是BeanDefinitionHolder类型
else if (value instanceof BeanDefinitionHolder) {
BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value;
return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());
}
//如果属性值是BeanDefinition类型
else if (value instanceof BeanDefinition) {
BeanDefinition bd = (BeanDefinition) value;
String innerBeanName = "(inner bean)" + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR +
ObjectUtils.getIdentityHexString(bd);
return resolveInnerBean(argName, innerBeanName, bd);
}
//如果属性值是DependencyDescriptor类型
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) {
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) {
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) {
return resolveManagedList(argName, (List<?>) value);
}
//如果属性值是Set类型
else if (value instanceof ManagedSet) {
return resolveManagedSet(argName, (Set<?>) value);
}
//如果属性值是Map类型
else if (value instanceof ManagedMap) {
return resolveManagedMap(argName, (Map<?, ?>) value);
}
//如果属性值是Properies类型
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;
}
//如果是TypedStringValue类型
else if (value instanceof TypedStringValue) {
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) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Error converting typed String value for " + argName, ex);
}
}
//如果属性值是空bean类型
else if (value instanceof NullBean) {
return null;
}
else {
//否则按字符串类型处理
return evaluate(value);
}
}该方法对不同的value类型,使用不同的方法进行解析,主要包含下面这些类型:
- RuntimeBeanReference:bean的引用类型。
- RuntimeBeanNameReference:bean名称的引用类型。
- BeanDefinitionHolder:BeanDefinition持有对象类型。
- BeanDefinition:bean的定义对象类型。
- DependencyDescriptor:依赖描述类型。
- ManagedArray:数组类型。
- ManagedList:List集合类型。
- ManagedSet:Set集合类型。
- ManagedMap:Map集合类型。
- ManagedProperties:Properties集合类型。
- TypedStringValue:字符串的type和值类型。
- NullBean:空bean类型。
- String:字符串类型。
- String[]:字符串数组类型。
- 其他类型。
从上面可以看到对value进行解析的方法有很多,我们挑其中一些比较重要的方法给大家讲解一下。
2 resolveReference方法
对于属性值的解析,要考虑引用类型的情况,在Spring的XML文件中,支持配置这样的参数:
表示user1引用了user,我们获取到的其实是user对应的bean实例。
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
try {
Object bean;
//获取引用bean的类型
Class<?> beanType = ref.getBeanType();
//如果引用bean要使用父容器加载
if (ref.isToParent()) {
//获取父容器
BeanFactory parent = this.beanFactory.getParentBeanFactory();
//如果父容器为空,则抛异常
if (parent == null) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Cannot resolve reference to bean " + ref +
" in parent factory: no parent factory available");
}
//如果引用bean的类型不为空,则从父容器中beanType获取bean实例
if (beanType != null) {
bean = parent.getBean(beanType);
}
//否则,从父容器中beanName获取bean实例
else {
bean = parent.getBean(String.valueOf(doEvaluate(ref.getBeanName())));
}
}
//如果不使用父容器加载
else {
String resolvedName;
//如果引用bean的类型不为空
if (beanType != null) {
NamedBeanHolder<?> namedBean = this.beanFactory.resolveNamedBean(beanType);
bean = namedBean.getBeanInstance();
resolvedName = namedBean.getBeanName();
}
//否则
else {
//获取已解析的beanName,主要是有EL表达式的情况
resolvedName = String.valueOf(doEvaluate(ref.getBeanName()));
//从当前容器中beanName获取bean实例
bean = this.beanFactory.getBean(resolvedName);
}
//将引用的beanName注册到Spring容器中
this.beanFactory.registerDependentBean(resolvedName, this.beanName);
}
//如果从容器中获取了空bean
if (bean instanceof NullBean) {
//将bean设置为空
bean = null;
}
//返回bean实例
return bean;
}
catch (BeansException ex) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
}
}下面用一张图总结一下,resolveReference方法的主要流程:
当然不同版本的Spring源码,这个流程可能有一点区别。
但是其主要思路是差不多的。
3.resolveInnerBean方法
resolveInnerBean方法主要是为了解析内部bean实例的。
下面用一张图总结一下,resolveInnerBean的主要流程:
4.resolveManagedList方法
resolveManagedList方法主要是用来解析List集合的。
这个方法的逻辑非常简单,当遇到List集合时,说白了会遍历集合,获取当中的每一个元素,调用resolveValueIfNecessary方法一个个解析。
想ManagedArray、resolveManagedSet、ManagedMap都是类似的思路,在这里就不过多介绍了。
5. evaluate方法
最后一起看看evaluate方法,它会对字符串或者字符串数组类型的属性值进行解析。
evaluate方法的逻辑是比较简单的,在这里就不画流程图了。
看到这里可能有些小伙伴会问题,为什么字符串类型的属性值,还需要调用doEvaluate方法再去解析一下,到底在解析什么?
下一篇文章会告诉你答案。