spring–属性填充之类型转换
文章目录
1 类型转换
先看下面这个小例子,我们在配置文件中定义如下:
<bean id="user" class="com.lx.converter.domain.User">
<!--name是一个String类型值-->
<property name="name" value="lx"></property>
<!--age是一个int类型值-->
<property name="age" value="12"></property>
</bean>
spring
读取配置文件后会自动给我们生成一个User
对象,并按照我们在配置文件中设置的属性自动给字段赋值。现在问题就来了,name
属性好说,它是String
类型的,我们填写的值也是String
,但是age
属性呢,我们填写的是String
类型,但是User
类中定义的是int
类型啊,那么spring
肯定在我们看不见的地方将String
->int
类型转换。
2 属性填充
spring
为什么能自动的将我们填写在XML
中的String
字符串转换为bean
对象合适的属性呢?
我们定位到spring
给bean
填充属性的方法,它肯定是在这里面实现的
/**
* Populate the bean instance in the given BeanWrapper with the property values
* from the bean definition.
* @param beanName the name of the bean
* @param mbd the bean definition for the bean
* @param bw the BeanWrapper with bean instance
*/
@SuppressWarnings("deprecation") // for postProcessPropertyValues
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
if (bw == null) {
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// Skip property population phase for null instance.
return;
}
}
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
}
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
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);
}
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
}
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
}
/*************************************************************************/
//上面一大堆前几篇博客已经讲过了,这里就不说了
if (pvs != null) {
//将PropertyValues中的值类型转换之后填充到实例中
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
这个
PropertyValues
是一个什么东西呢?
- 在
4
章节中我们看它的继承体系发现,它实际上就相当于一个PropertyValue
的集合,而PropertyValue
就代表一个需要被填充的属性,里面保存了属性名,原始值(String
),转换后的值(当然,现在还是null
,因为此时还未进行类型转换)等。spring
在属性填充阶段,遍历PropertyValues
,对每一个PropertyValue
都进行类型转换,然后在使用反射填充属性值
3 MutablePropertyValues
spring
中设计用来保存需要填充到bean
对象中属性值的
3.1 MutablePropertyValues
的继承体系
我们先来看一下它的UML
图
我们再来看一看这两个接口的作用
下面是MutablePropertyValues
类的字段
public class MutablePropertyValues implements PropertyValues, Serializable {
//PropertyValue代表一个需要执行setter方法的属性
private final List<PropertyValue> propertyValueList;
//处理的属性
@Nullable
private Set<String> processedProperties;
//标识所有属性是否已经完成类型转换
private volatile boolean converted = false;
}
总结:
Iterable
是JDK
中的一个接口,第一个方法返回一个迭代器,第二个则表示可使用forEach
方法快速迭代,总之,这个接口就是用来定义迭代方法的。PropertyValues
继承了Iterable<PropertyValue>
,并增加了一些方法,来获取这个数据结构存储的内容PropertyValue
。MutablePropertyValues
呢,实际上是有一个属性private final List<PropertyValue> propertyValueList;
,它的迭代功能就是借助了List
集合实现的。
3.2 PropertyValue
的继承体系
看上面继承关系我们就知道
AttributeAccessorSupport
实现了AttributeAccessor
接口的功能,BeanMetadataAttributeAccessor
只实现了BeanMetadataElement
接口的功能,但是BeanMetadataAttributeAccessor
又继承了AttributeAccessorSupport
,所以它同时拥有的两个接口的功能。spring
就是通过这种方式一层一层扩展一个类的功能,典型的就是工厂DefaultListableBeanFactory
我们再看一下这两个重要接口的方法
总结:
AttributeAccessor
是属性访问器,定义了增删查方法,也就是说我们的PropertyValue
可以通过这些方法对某个Bean
对象的属性进行修改,对比一下PropertyValue
和AbstractBeanDefinition
,你会发现AbstractBeanDefinition
也实现了这些接口,其实如果你看过我前面几篇文章的话,现在就应该知道,第五篇ConfigurationClassPostProcessor
中,我们在检查出某一个组件是配置类的时候,我们调用了setAttribute
方法向BeanDefinition
中添加了一个标记,表明该配置类是full
还是lite
。BeanMetadataElement
这里它的作用是用来保存未进行类型转换的原始PropertyValue
,它定义了一个方法用来获取这个对象。这个东西也在我们第五篇讲ConfigurationClassPostProcessor
用到了,解析@Bean
方法的时候,spring
会将该方法的MethodMetadata
存入source
(在它的实现类BeanMetadataAttributeAccessor
中定义了source
的set
方法)中。
我们看一下AttributeAccessorSupport
这个类
public abstract class AttributeAccessorSupport implements AttributeAccessor, Serializable {
/** Map with String keys and Object values. */
private final Map<String, Object> attributes = new LinkedHashMap<>();
@Override
public void setAttribute(String name, @Nullable Object value) {
Assert.notNull(name, "Name must not be null");
if (value != null) {
this.attributes.put(name, value);
}
else {
removeAttribute(name);
}
}
@Override
@Nullable
public Object getAttribute(String name) {
Assert.notNull(name, "Name must not be null");
return this.attributes.get(name);
}
@Override
@Nullable
public Object removeAttribute(String name) {
Assert.notNull(name, "Name must not be null");
return this.attributes.remove(name);
}
@Override
public boolean hasAttribute(String name) {
Assert.notNull(name, "Name must not be null");
return this.attributes.containsKey(name);
}
@Override
public String[] attributeNames() {
return StringUtils.toStringArray(this.attributes.keySet());
}
/**
* Copy the attributes from the supplied AttributeAccessor to this accessor.
* @param source the AttributeAccessor to copy from
*/
protected void copyAttributesFrom(AttributeAccessor source) {
Assert.notNull(source, "Source must not be null");
String[] attributeNames = source.attributeNames();
for (String attributeName : attributeNames) {
setAttribute(attributeName, source.getAttribute(attributeName));
}
}
@Override
public boolean equals(@Nullable Object other) {
return (this == other || (other instanceof AttributeAccessorSupport &&
this.attributes.equals(((AttributeAccessorSupport) other).attributes)));
}
@Override
public int hashCode() {
return this.attributes.hashCode();
}
}
里面保存了一个map
,然后定义了几个操作map
的方法,逻辑很简单,也就是说谁继承了AttributeAccessorSupport
,谁就相当于在类中定义了一个map
,并给它整了一套增删查的方法。
PropertyValue
继承了它。
public class PropertyValue extends BeanMetadataAttributeAccessor implements Serializable {
//属性名
private final String name;
@Nullable
//原始值
private final Object value;
//属性是否是一个Optional容器
private boolean optional = false;
//是否被转换
private boolean converted = false;
@Nullable
//转换后的值
private Object convertedValue;
/** Package-visible field that indicates whether conversion is necessary. */
@Nullable
//是否需要被转换
volatile Boolean conversionNecessary;
/** Package-visible field for caching the resolved property path tokens. */
@Nullable
transient volatile Object resolvedTokens;
}
其实这里面定义的才是PropertyValue
的核心属性,虽然上面说了一堆的AttributeAccessor
,但其实很少用到那个Map
集合。
3.2.1 构造方法
/**
* Constructor that exposes a new value for an original value holder.
* The original holder will be exposed as source of the new holder.
* @param original the PropertyValue to link to (never {@code null})
* @param newValue the new value to apply
*/
public PropertyValue(PropertyValue original, @Nullable Object newValue) {
Assert.notNull(original, "Original must not be null");
this.name = original.getName();
//新值给了value字段
this.value = newValue;
this.optional = original.isOptional();
this.conversionNecessary = original.conversionNecessary;
this.resolvedTokens = original.resolvedTokens;
//BeanMetadataElement定义的方法在这里就用到了,保存原始的PropertyValue
setSource(original);
//还需要拷贝AttributeAccessor接口实现的Map集合
copyAttributesFrom(original);
}
该构造方法使用经过
BeanDefinitionValueResolver
初步解析的值覆盖原来的旧值,重新构造了一个PropertyValue
对象需要注意
3.2.1
和3.2.2
的区别
3.2.2
保存类型转换成功的值3.2.1
保存初步解析的值,此时还未进行类型转换
3.2.2 setConvertedValue(@Nullable Object value)
方法,保存已经类型转换成功的值到PropertyValue
中
/**
* Set the converted value of this property value,
* after processed type conversion.
*/
public synchronized void setConvertedValue(@Nullable Object value) {
//表示已类型转换
this.converted = true;
//保存到了convertedValue属性中
this.convertedValue = value;
}
3.2.3 getOriginalPropertyValue()
方法,获取原始的PropertyValue
对象
/**
* Return the original PropertyValue instance for this value holder.
* @return the original PropertyValue (either a source of this
* value holder or this value holder itself).
*/
public PropertyValue getOriginalPropertyValue() {
PropertyValue original = this;
//原始的PropertyValue通过setSource()方法保存进去,现在通过getSource()方法取出
Object source = getSource();
//循环,取出最原始的PropertyValue
while (source instanceof PropertyValue && source != original) {
original = (PropertyValue) source;
source = original.getSource();
}
return original;
}
- 在
4
中,如果填充的属性是嵌套属性,那么就会重新构建一个PropertyValue
对象,此时原始的对象就会通过setSource()
方法缓存到新PropertyValue
对象中,这个过程见3.2.1
- 该方法被用到的地方:缓存属性名称标记
PropertyTokenHolder
4 applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs)
方法, 将MutablePropertyValues
中的属性值填充到实例中
/**
* Apply the given property values, resolving any runtime references
* to other beans in this bean factory. Must use deep copy, so we
* don't permanently modify this property.
* @param beanName the bean name passed for better exception information
* @param mbd the merged bean definition
* @param bw the BeanWrapper wrapping the target object
* @param pvs the new property values
*/
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
//没有属性,不需要填充,直接返回
if (pvs.isEmpty()) {
return;
}
if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {
((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
}
MutablePropertyValues mpvs = null;
List<PropertyValue> original;
//spring中默认保存某个bean需要填充的属性的对象类型就是MutablePropertyValues
if (pvs instanceof MutablePropertyValues) {
mpvs = (MutablePropertyValues) pvs;
//MutablePropertyValues中保存的所有属性均已经进行了类型转换
if (mpvs.isConverted()) {
// Shortcut: use the pre-converted values as-is.
try {
//直接填充所有已经进行类型转换的属性,见4.3
bw.setPropertyValues(mpvs);
return;
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
/**
* 就是返回MutablePropertyValues中的那个List<PropertyValue>集合
* 在3.1中有过介绍
*/
original = mpvs.getPropertyValueList();
}
//spring中默认认为其他PropertyValues的实现是基于数组的
else {
original = Arrays.asList(pvs.getPropertyValues());
}
/**
* 获取用户自定义的TypeConverter
* 如果用户未指定工厂中的TypeConverter,就使用默认的TypeConverter
* BeanWrapper实现了TypeConverter接口,主要就是为了可以做类型转换
*/
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
//创建一个BeanDefinitionValueResolver,见5.1
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
// Create a deep copy, resolving any references for values.
List<PropertyValue> deepCopy = new ArrayList<>(original.size());
boolean resolveNecessary = false;
//遍历所有需要填充的属性,并进行类型转换
for (PropertyValue pv : original) {
//该属性已经进行类型转换了
if (pv.isConverted()) {
deepCopy.add(pv);
}
//该属性未进行类型转换,进行类型转换
else {
//获取需要填充的属性名
String propertyName = pv.getName();
//获取原始值(未进行类型装换的值)
Object originalValue = pv.getValue();
if (originalValue == AutowiredPropertyMarker.INSTANCE) {
Method writeMethod = bw.getPropertyDescriptor(propertyName).getWriteMethod();
if (writeMethod == null) {
throw new IllegalArgumentException("Autowire marker for property without write method: " + pv);
}
originalValue = new DependencyDescriptor(new MethodParameter(writeMethod, 0), true);
}
//初步解析属性值,见5.2
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
Object convertedValue = resolvedValue;
/**
* isWritableProperty()使用内省判断该属性是否可写,即判断该属性有没有setter方法
* 若是嵌套属性,则属性必须有初始值,且属性必须有对应的getter方法,这个方法的源码见下篇
* 文章(专讲BeanWrapper)
* isNestedOrIndexedProperty()判断给定属性是否是一个索引或嵌套属性,见4.1
*/
boolean convertible = bw.isWritableProperty(propertyName) &&
!PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
/**
* 经过判断,表明该属性可以进行类型转换
* 类型转换,见4.2
*/
if (convertible) {
convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
}
// Possibly store converted value in merged bean definition,
// in order to avoid re-conversion for every created bean instance.
//初步解析的属性值和原始的属性值相等
if (resolvedValue == originalValue) {
/**
* 可转换,此时已经进行了类型转换
* 将转换后的值存入PropertyValue中,见3.2.2
*/
if (convertible) {
pv.setConvertedValue(convertedValue);
}
deepCopy.add(pv);
}
/**
* 可转换,此时已经进行了类型转换
* 原始值为TypedStringValue类型,且非动态,非数组,非集合
*/
else if (convertible && originalValue instanceof TypedStringValue &&
!((TypedStringValue) originalValue).isDynamic() &&
!(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
//保存已经类型转换的值到PropertyValue中,见3.2.2
pv.setConvertedValue(convertedValue);
deepCopy.add(pv);
}
/**
* 其他情况,则每次创建新对象时都需要重新进行类型转换
* 对于嵌套属性,肯定走这个分支,比如role.rolename
*/
else {
resolveNecessary = true;
/**
* 使用初步解析的属性值convertedValue(实际上就是resolvedValue)覆盖原始值,
* 重新构造一个PropertyValue对象,见3.2.1
*/
deepCopy.add(new PropertyValue(pv, convertedValue));
}
}
}
/**
* 标记所有属性全部完成类型转换
* 此时里面存储了所有属性的原始值和转换后的值
* 下次创建对象的时候就不用再次进行类型转换了,而是直接赋值
*/
if (mpvs != null && !resolveNecessary) {
mpvs.setConverted();
}
// Set our (possibly massaged) deep copy.
/**
* 使用deepCopy这个list集合重新构造一个MutablePropertyValues
* 填充所有已经进行类型转换的属性,见4.3
*/
try {
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
4.1 判断给定属性是否是一个索引或嵌套属性
/**
* Check whether the given property path indicates an indexed or nested property.
* @param propertyPath the property path to check
* @return whether the path indicates an indexed or nested property
*/
public static boolean isNestedOrIndexedProperty(@Nullable String propertyPath) {
if (propertyPath == null) {
return false;
}
for (int i = 0; i < propertyPath.length(); i++) {
char ch = propertyPath.charAt(i);
//NESTED_PROPERTY_SEPARATOR_CHAR = '.';
//PROPERTY_KEY_PREFIX = "[";
if (ch == PropertyAccessor.NESTED_PROPERTY_SEPARATOR_CHAR ||
ch == PropertyAccessor.PROPERTY_KEY_PREFIX_CHAR) {
return true;
}
}
return false;
}
对属性名字符进行遍历,判断里面有没有
.
或者[
符号
4.2 类型转换
/**
* Convert the given value for the specified target property.
*/
@Nullable
private Object convertForProperty(
@Nullable Object value, String propertyName, BeanWrapper bw, TypeConverter converter) {
/***************************默认的转换器转换**************************************/
if (converter instanceof BeanWrapperImpl) {
return ((BeanWrapperImpl) converter).convertForProperty(value, propertyName);
}
/***************************用户自定义的转换器转换*********************************/
else {
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
//得到属性setter方法的参数
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
return converter.convertIfNecessary(value, pd.getPropertyType(), methodParam);
}
}
无论是用户自定义的转换器转换还是默认的转换器转换最终都是调用了转换器的
convertIfNecessary
方法
/**
* Convert the given value for the specified property to the latter's type.
* <p>This method is only intended for optimizations in a BeanFactory.
* Use the {@code convertIfNecessary} methods for programmatic conversion.
* @param value the value to convert
* @param propertyName the target property
* (note that nested or indexed properties are not supported here)
* @return the new value, possibly the result of type conversion
* @throws TypeMismatchException if type conversion failed
*/
@Nullable
public Object convertForProperty(@Nullable Object value, String propertyName) throws TypeMismatchException {
/**
* 获取当前缓存的bean的内省结果
* CachedIntrospectionResults是BeanWrapperImpl的一个字段,4中调用isWritableProperty()
* 方法时使用了内省机制,得到了当前bean的内省结果,并保存到了BeanWrapperImpl对象中
* 此处只是简单的将字段值取出
* 有关内省的方法源码都在下篇文章
*/
CachedIntrospectionResults cachedIntrospectionResults = getCachedIntrospectionResults();
/**
* 获取propertyName的PropertyDescriptor属性描述
* 有关内省的方法源码都在下篇文章
*/
PropertyDescriptor pd = cachedIntrospectionResults.getPropertyDescriptor(propertyName);
if (pd == null) {
throw new InvalidPropertyException(getRootClass(), getNestedPath() + propertyName,
"No property '" + propertyName + "' found");
}
/**
* 获取当前缓存的当前bean的指定属性的TypeDescriptor类型描述
* 后面根据这个TypeDescriptor进行类型转换
* 有关内省的方法源码都在下篇文章
*/
TypeDescriptor td = cachedIntrospectionResults.getTypeDescriptor(pd);
/**
* 第一次肯定是不存在的,需要手动创建一个对应的TypeDescriptor,加入到缓存中
* 构建对应属性的TypeDescriptor要转换的类型描述,见4.2.1
*/
if (td == null) {
td = cachedIntrospectionResults.addTypeDescriptor(pd, new TypeDescriptor(property(pd)));
}
//依据TypeDescriptor进行类型转换,见4.2.2
return convertForProperty(propertyName, null, value, td);
}
最终实现类型转换的方法
convertForProperty(propertyName, null, value, td)
,这个方法在多处被调用,在4.3
章节中,类型转换嵌套属性也是使用该方法
4.2.1 构建对应属性的TypeDescriptor
类型描述
TypeDescriptor
是spring
定义的要转换的类型描述
Property
spring
定义的 用来描述一个javaBean
属性
这个property
方法构造了一个Property
对象
private Property property(PropertyDescriptor pd) {
/**
* spring内省forClass()方法得到的PropertyDescriptor就是
* GenericTypeAwarePropertyDescriptor类型的,所以这里可以直接强转
*/
GenericTypeAwarePropertyDescriptor gpd = (GenericTypeAwarePropertyDescriptor) pd;
//创建一个Property对象,通过它来构建对应属性的TypeDescriptor
return new Property(gpd.getBeanClass(), gpd.getReadMethod(), gpd.getWriteMethod(), gpd.getName());
}
看一下Property
类的属性,基本囊括了一个JavaBean
属性所拥有的全部描述
public final class Property {
private static Map<Property, Annotation[]> annotationCache = new ConcurrentReferenceHashMap<>();
private final Class<?> objectType;
@Nullable
private final Method readMethod;
@Nullable
private final Method writeMethod;
private final String name;
private final MethodParameter methodParameter;
@Nullable
private Annotation[] annotations;
//使用的是这个构造方法创建的Property对象
public Property(
Class<?> objectType, @Nullable Method readMethod, @Nullable Method writeMethod, @Nullable String name) {
this.objectType = objectType;
this.readMethod = readMethod;
this.writeMethod = writeMethod;
//解析getter和setter方法参数
this.methodParameter = resolveMethodParameter();
//根据方法名解析属性名
this.name = (name != null ? name : resolveName());
}
/**
* 解析getter和setter方法参数
* 从这个方法内容上看,优先使用setter方法的参数
* 当setter方法的参数为null或setter方法和getter方法的参数类型有继承关系的时候才用
* getter方法的参数
*/
private MethodParameter resolveMethodParameter() {
//获取读方法的方法参数对象
MethodParameter read = resolveReadMethodParameter();
//获取写方法的方法参数对象
MethodParameter write = resolveWriteMethodParameter();
if (write == null) {
if (read == null) {
//读写方法不能都没有参数
throw new IllegalStateException("Property is neither readable nor writeable");
}
//写方法没有参数就返回读方法的参数
return read;
}
if (read != null) {
Class<?> readType = read.getParameterType();
Class<?> writeType = write.getParameterType();
//读写方法参数不相同,并且具有继承关系则返回读方法参数
if (!writeType.equals(readType) && writeType.isAssignableFrom(readType)) {
return read;
}
}
return write;
}
/**
* 根据方法名解析属性名
* 从这个方法内容上看,优先使用getter方法的名字作为name的值
* getter方法可以以get或is开头,去掉前缀,第一个字母小写就是name的值
* setter方法只能以set开头,去掉前缀,第一个字母小写就是name的值
*/
private String resolveName() {
if (this.readMethod != null) {
int index = this.readMethod.getName().indexOf("get");
if (index != -1) {
index += 3;
}
else {
index = this.readMethod.getName().indexOf("is");
if (index == -1) {
throw new IllegalArgumentException("Not a getter method");
}
index += 2;
}
return StringUtils.uncapitalize(this.readMethod.getName().substring(index));
}
else if (this.writeMethod != null) {
int index = this.writeMethod.getName().indexOf("set");
if (index == -1) {
throw new IllegalArgumentException("Not a setter method");
}
index += 3;
return StringUtils.uncapitalize(this.writeMethod.getName().substring(index));
}
else {
throw new IllegalStateException("Property is neither readable nor writeable");
}
}
/**
* The property type: e.g. {@code java.lang.String}
*/
public Class<?> getType() {
return this.methodParameter.getParameterType();
}
}
再看一下TypeDescriptor
类的属性
public class TypeDescriptor implements Serializable {
private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
private static final Map<Class<?>, TypeDescriptor> commonTypesCache = new HashMap<>(32);
private static final Class<?>[] CACHED_COMMON_TYPES = {
boolean.class, Boolean.class, byte.class, Byte.class, char.class, Character.class,
double.class, Double.class, float.class, Float.class, int.class, Integer.class,
long.class, Long.class, short.class, Short.class, String.class, Object.class};
static {
for (Class<?> preCachedClass : CACHED_COMMON_TYPES) {
commonTypesCache.put(preCachedClass, valueOf(preCachedClass));
}
}
//最终要转换的类型
private final Class<?> type;
//类型解析器
private final ResolvableType resolvableType;
private final AnnotatedElementAdapter annotatedElement;
/**
* Create a new type descriptor from a {@link Property}.
* <p>Use this constructor when a source or target conversion point is a
* property on a Java class.
* @param property the property
*/
public TypeDescriptor(Property property) {
Assert.notNull(property, "Property must not be null");
//获取解析当前方法参数的类型解析器
this.resolvableType = ResolvableType.forMethodParameter(property.getMethodParameter());
/**
* 类型解析器解析方法参数的类型
* 上一步调用forMethodParameter的时候就已经将类型解析出来了
* 例如解析List<User>这种属性,它的类型是java.util.List<com.lx.converter.domain.User>
* 这一步只不过验证是否解析成功,解析成功使用上一步解析出来的resolved,
* 否则使用property.getType()(最终使用标准反射获取MethodParameter的类型)
*/
this.type = this.resolvableType.resolve(property.getType());
this.annotatedElement = new AnnotatedElementAdapter(property.getAnnotations());
}
}
ResolvableType
类型解析器,里面有两个关键属性。
public class ResolvableType implements Serializable {
/**
* The underlying Java type being managed.
* 这个会保存泛型信息
* 例如解析List<User>这种属性,它里面会保存java.util.List<com.lx.converter.domain.User>
*/
private final Type type;
/**
* 保存的是最终被转换的类型的clazz对象
* 例如解析List<User>这种属性,它的值就是java.util.List.class
*
*/
@Nullable
private Class<?> resolved;
/**
* Resolve this type to a {@link java.lang.Class}, returning the specified
* {@code fallback} if the type cannot be resolved. This method will consider bounds
* of {@link TypeVariable TypeVariables} and {@link WildcardType WildcardTypes} if
* direct resolution fails; however, bounds of {@code Object.class} will be ignored.
* @param fallback the fallback class to use if resolution fails
* @return the resolved {@link Class} or the {@code fallback}
* @see #resolve()
* @see #resolveGeneric(int...)
* @see #resolveGenerics()
*/
public Class<?> resolve(Class<?> fallback) {
//这一步只不过验证是否解析成功,解析成功使用解析出来的resolved,
//否则使用property.getType()(最终使用标准反射获取MethodParameter的类型)
return (this.resolved != null ? this.resolved : fallback);
}
}
4.2.2 依据TypeDescriptor
进行类型转换,具体实现委托给了TypeConverterDelegate
protected Object convertForProperty(
String propertyName, @Nullable Object oldValue, @Nullable Object newValue, TypeDescriptor td)
throws TypeMismatchException {
//调用了内部私有方法实现类型转换
return convertIfNecessary(propertyName, oldValue, newValue, td.getType(), td);
}
/**
* 使用委托模式将内部的复杂的类型转换逻辑交给了TypeConverterDelegate
*/
private Object convertIfNecessary(@Nullable String propertyName, @Nullable Object oldValue,
@Nullable Object newValue, @Nullable Class<?> requiredType, @Nullable TypeDescriptor td)
throws TypeMismatchException {
Assert.state(this.typeConverterDelegate != null, "No TypeConverterDelegate");
try {
/**
* 具体的类型转换逻辑委派给了TypeConverterDelegate,由这个类的convertIfNecessary方法实现
* 该字段初始化是在BeanWrapperImpl初始化的时候,详情见下篇文章
*/
return this.typeConverterDelegate.convertIfNecessary(propertyName, oldValue, newValue, requiredType, td);
}
catch (ConverterNotFoundException | IllegalStateException ex) {
PropertyChangeEvent pce =
new PropertyChangeEvent(getRootInstance(), this.nestedPath + propertyName, oldValue, newValue);
throw new ConversionNotSupportedException(pce, requiredType, ex);
}
catch (ConversionException | IllegalArgumentException ex) {
PropertyChangeEvent pce =
new PropertyChangeEvent(getRootInstance(), this.nestedPath + propertyName, oldValue, newValue);
throw new TypeMismatchException(pce, requiredType, ex);
}
}
由TypeConverterDelegate
这个类的convertIfNecessary()
方法实现类型转换
/**
* Convert the value to the required type (if necessary from a String),
* for the specified property.
* @param propertyName name of the property
* @param oldValue the previous value, if available (may be {@code null})
* @param newValue the proposed new value
* @param requiredType the type we must convert to
* (or {@code null} if not known, for example in case of a collection element)
* @param typeDescriptor the descriptor for the target property or field
* @return the new value, possibly the result of type conversion
* @throws IllegalArgumentException if type conversion failed
*/
@SuppressWarnings("unchecked")
@Nullable
public <T> T convertIfNecessary(@Nullable String propertyName, @Nullable Object oldValue, @Nullable Object newValue,
@Nullable Class<T> requiredType, @Nullable TypeDescriptor typeDescriptor) throws IllegalArgumentException {
// Custom editor for this type?
//从用户自定义的PropertyEditor中找到可以将String->requiredType的PropertyEditor
PropertyEditor editor = this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName);
ConversionFailedException conversionAttemptEx = null;
/*****************************使用conversionService转换*****************************/
// No custom editor but custom ConversionService specified?
//获取统一转换服务
ConversionService conversionService = this.propertyEditorRegistry.getConversionService();
/**
* 只有从用户自定义的PropertyEditor找不到合适的
* 才会尝试使用ConversionService进行类型转换
*/
if (editor == null && conversionService != null && newValue != null && typeDescriptor != null) {
//得到待转换值的属性描述
TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue);
/**
* 判断统一转换服务能否实现sourceTypeDesc->typeDescriptor的转换
* sourceTypeDesc:待转换值的类型描述
* typeDescriptor:要求类型的类型描述
*/
if (conversionService.canConvert(sourceTypeDesc, typeDescriptor)) {
try {
return (T) conversionService.convert(newValue, sourceTypeDesc, typeDescriptor);
}
catch (ConversionFailedException ex) {
// fallback to default conversion logic below
conversionAttemptEx = ex;
}
}
}
Object convertedValue = newValue;
/********************************使用PropertyEditor转换*****************************/
// Value not of required type?
/**
* 此处两种情况进入类型转换过程
* 1.用户自定义了String->requiredType转换的PropertyEditor
* 2.requiredType和现有的值的类型不匹配
*/
if (editor != null || (requiredType != null && !ClassUtils.isAssignableValue(requiredType, convertedValue))) {
//String->Collection
if (typeDescriptor != null && requiredType != null && Collection.class.isAssignableFrom(requiredType) &&
convertedValue instanceof String) {
//获取类型的元素类型(array,collection,stream中存的元素类型)
TypeDescriptor elementTypeDesc = typeDescriptor.getElementTypeDescriptor();
if (elementTypeDesc != null) {
Class<?> elementType = elementTypeDesc.getType();
//元素类型为clazz或枚举
if (Class.class == elementType || Enum.class.isAssignableFrom(elementType)) {
//将逗号分隔的字符串转化为字符串数组
convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
}
}
}
if (editor == null) {
//从默认的PropertyEditor中找到可以将String->requiredType转换的PropertyEditor
editor = findDefaultEditor(requiredType);
}
//使用PropertyEditor转换String->requiredType
convertedValue = doConvertValue(oldValue, convertedValue, requiredType, editor);
}
/*******************************************************************************/
boolean standardConversion = false;
if (requiredType != null) {
/******************************标准类型转换**************************/
// Try to apply some standard type conversion rules if appropriate.
if (convertedValue != null) {
//属性是Object类型,则无需类型转换
if (Object.class == requiredType) {
return (T) convertedValue;
}
//属性是数组类型
else if (requiredType.isArray()) {
// Array required -> apply appropriate conversion of elements.
if (convertedValue instanceof String && Enum.class.isAssignableFrom(requiredType.getComponentType())) {
convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
}
return (T) convertToTypedArray(convertedValue, propertyName, requiredType.getComponentType());
}
//属性是集合类型
else if (convertedValue instanceof Collection) {
// Convert elements to target type, if determined.
convertedValue = convertToTypedCollection(
(Collection<?>) convertedValue, propertyName, requiredType, typeDescriptor);
standardConversion = true;
}
//属性是Map集合类型,此处只会转化Map集合key和value的类型,并不是将别的集合转为Map
else if (convertedValue instanceof Map) {
// Convert keys and values to respective target type, if determined.
convertedValue = convertToTypedMap(
(Map<?, ?>) convertedValue, propertyName, requiredType, typeDescriptor);
standardConversion = true;
}
//属性为非数组类型,但填充值为数组类型,那么就取数组的第一个值进行类型转换之后填充
if (convertedValue.getClass().isArray() && Array.getLength(convertedValue) == 1) {
convertedValue = Array.get(convertedValue, 0);
standardConversion = true;
}
/**
* isPrimitiveOrWrapper()判断这个类是不是一个原始类型
* ( boolean, byte, char, short, int, long, float, or double,void)
* 或者包装类型
* (Boolean, Byte, Character, Short, Integer, Long, Float,Double, or Void)
* 这个分支处理原始或包装类型->String类型的转换
*/
if (String.class == requiredType && ClassUtils.isPrimitiveOrWrapper(convertedValue.getClass())) {
// We can stringify any primitive value...
return (T) convertedValue.toString();
}
/**
* 通过构造方法进行类型转换
* 直接获取转换类型类的单String参数的构造器,传入需要转换的值
* 用户在这个构造器中编写转换逻辑,spring通过这个构造器构造转换成功的对象
* 这种方式只能实现String->requiredType的转换
*/
else if (convertedValue instanceof String && !requiredType.isInstance(convertedValue)) {
//requiredType不是接口,不是枚举
if (conversionAttemptEx == null && !requiredType.isInterface() && !requiredType.isEnum()) {
try {
//得到单String参数的构造器
Constructor<T> strCtor = requiredType.getConstructor(String.class);
/**
* 使用这个构造器实例化一个requiredType对象
* 如此也实现了String->requiredType的转换
*/
return BeanUtils.instantiateClass(strCtor, convertedValue);
}
catch (NoSuchMethodException ex) {
// proceed with field lookup
if (logger.isTraceEnabled()) {
logger.trace("No String constructor found on type [" + requiredType.getName() + "]", ex);
}
}
catch (Exception ex) {
if (logger.isDebugEnabled()) {
logger.debug("Construction via String failed for type [" + requiredType.getName() + "]", ex);
}
}
}
//requiredType是枚举,String->enum
String trimmedValue = ((String) convertedValue).trim();
if (requiredType.isEnum() && trimmedValue.isEmpty()) {
// It's an empty enum identifier: reset the enum value to null.
return null;
}
convertedValue = attemptToConvertStringToEnum(requiredType, trimmedValue, convertedValue);
standardConversion = true;
}
//Number->Number
else if (convertedValue instanceof Number && Number.class.isAssignableFrom(requiredType)) {
convertedValue = NumberUtils.convertNumberToTargetClass(
(Number) convertedValue, (Class<Number>) requiredType);
standardConversion = true;
}
}
//待转换的值为null,此时创建一个空容器代表已转化的值
else {
// convertedValue == null
if (requiredType == Optional.class) {
convertedValue = Optional.empty();
}
}
/***********************未转换成功才会运行下面代码**************************/
//convertedValue是不是requiredType类型
if (!ClassUtils.isAssignableValue(requiredType, convertedValue)) {
//抛出前面转换过程产生的异常
if (conversionAttemptEx != null) {
// Original exception from former ConversionService call above...
throw conversionAttemptEx;
}
//用户自定义的PropertyEditor未转换成功,此时使用conversionService进行转换
else if (conversionService != null && typeDescriptor != null) {
// ConversionService not tried before, probably custom editor found
// but editor couldn't produce the required type...
//得到待转换值的类型描述
TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue);
/**
* 判断统一转换服务能否实现sourceTypeDesc->typeDescriptor的转换
* sourceTypeDesc:待转换值的类型描述
* typeDescriptor:要求类型的类型描述
*/
if (conversionService.canConvert(sourceTypeDesc, typeDescriptor)) {
//统一转换服务转换类型
return (T) conversionService.convert(newValue, sourceTypeDesc, typeDescriptor);
}
}
//后面都是异常相关处理
// Definitely doesn't match: throw IllegalArgumentException/IllegalStateException
StringBuilder msg = new StringBuilder();
msg.append("Cannot convert value of type '").append(ClassUtils.getDescriptiveType(newValue));
msg.append("' to required type '").append(ClassUtils.getQualifiedName(requiredType)).append("'");
if (propertyName != null) {
msg.append(" for property '").append(propertyName).append("'");
}
if (editor != null) {
msg.append(": PropertyEditor [").append(editor.getClass().getName()).append(
"] returned inappropriate value of type '").append(
ClassUtils.getDescriptiveType(convertedValue)).append("'");
throw new IllegalArgumentException(msg.toString());
}
else {
msg.append(": no matching editors or conversion strategy found");
throw new IllegalStateException(msg.toString());
}
}
}
//抛出前面转换过程产生的异常
if (conversionAttemptEx != null) {
if (editor == null && !standardConversion && requiredType != null && Object.class != requiredType) {
throw conversionAttemptEx;
}
logger.debug("Original ConversionService attempt failed - ignored since " +
"PropertyEditor based conversion eventually succeeded", conversionAttemptEx);
}
//返回转换成功的值
return (T) convertedValue;
}
4.3 填充属性(嵌套属性可能还未进行类型转换)
public void setPropertyValues(PropertyValues pvs) throws BeansException {
//调用重载的方法进行属性填充
setPropertyValues(pvs, false, false);
}
该方法的源码在下篇文章。
先说一下该方法的大致流程:
- 遍历
MutablePropertyValues
,按顺序填充每一个PropertyValue
属性- 解析填充属性的属性名,得到
PropertyTokenHolder
属性名称标记(里面有真实属性名和规范属性名)- 调用
getLocalPropertyHandler(tokens.actualName)
方法得到属性的属性处理器PropertyHandler
- 验证属性是否包含
setter
方法,没有就抛异常- 判断
PropertyValue
属性是否有必要进行类型转换,没有必要就直接通过PropertyHandler
属性处理器ph.setValue(valueToApply)
方法完成属性赋值,否则就进入6
- 判断
PropertyValue
属性是否已经经过类型转换,未经过类型转换就先类型转换,然后填充属性值,否则直接填充属性值
5 BeanDefinitionValueResolver
帮助类,将用户在
XML
文件中定义的属性值解析为目标bean
实例的实际值
先来看一下它的属性
class BeanDefinitionValueResolver {
//spring工厂对象
private final AbstractAutowireCapableBeanFactory beanFactory;
private final String beanName;
private final BeanDefinition beanDefinition;
//类型转换器
private final TypeConverter typeConverter;
}
5.1 构造方法
/**
* Create a BeanDefinitionValueResolver for the given BeanFactory and BeanDefinition.
* @param beanFactory the BeanFactory to resolve against
* @param beanName the name of the bean that we work on
* @param beanDefinition the BeanDefinition of the bean that we work on
* @param typeConverter the TypeConverter to use for resolving TypedStringValues
*/
public BeanDefinitionValueResolver(AbstractAutowireCapableBeanFactory beanFactory, String beanName,
BeanDefinition beanDefinition, TypeConverter typeConverter) {
this.beanFactory = beanFactory;
this.beanName = beanName;
this.beanDefinition = beanDefinition;
this.typeConverter = typeConverter;
}
需要为每一个进行属性填充的
bean
创建自己的BeanDefinitionValueResolver
对象,解析属性值
5.2 resolveValueIfNecessary(Object argName, @Nullable Object value)
方法,初步解析属性值
其实就是把那些不常见的类型转化为常见的类型,以String
和Map
为例
/**
* Given a PropertyValue, return a value, resolving any references to other
* beans in the factory if necessary. The value could be:
* <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.
* <li>A RuntimeBeanReference, which must be resolved.
* <li>A ManagedList. This is a special collection that may contain
* RuntimeBeanReferences or Collections that will need to be resolved.
* <li>A ManagedSet. May also contain RuntimeBeanReferences or
* Collections that will need to be resolved.
* <li>A ManagedMap. In this case the value may be a RuntimeBeanReference
* or Collection that will need to be resolved.
* <li>An ordinary object or {@code null}, in which case it's left alone.
* @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.
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);
}
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.
return resolveManagedSet(argName, (Set<?>) value);
}
/*************************************Map**********************************/
//5.2.1 Map集合解析
else if (value instanceof ManagedMap) {
// May need to resolve contained runtime references.
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;
}
/*************************************String**********************************/
//5.2.2 String解析
else if (value instanceof TypedStringValue) {
// Convert value to target type here.
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);
}
}
5.2.1 Map
集合类型解析
<property name="customEditors">
<map>
<entry key="com.lx.converter.domain.Role"
value="com.lx.converter.propertyEditor.StringToRolePropertyEditor"></entry>
</map>
</property>
在XML
中配置的Map
集合,经过XmlBeanDefinitionReader
解析生成一个ManagedMap
类型的对象。
进入resolveManagedMap
方法
/**
* For each element in the managed map, resolve reference if necessary.
*/
private Map<?, ?> resolveManagedMap(Object argName, Map<?, ?> mm) {
Map<Object, Object> resolved = new LinkedHashMap<>(mm.size());
mm.forEach((key, value) -> {
Object resolvedKey = resolveValueIfNecessary(argName, key);
Object resolvedValue = resolveValueIfNecessary(new KeyedArgName(argName, key), value);
resolved.put(resolvedKey, resolvedValue);
});
return resolved;
}
实际上就是将ManagedMap
类型转化为LinkedHashMap
类型。
5.2.2 String
类型解析
在XML
中配置的String
字符串,经过XmlBeanDefinitionReader
解析生成一个TypedStringValue
类型的对象,现在需要将它转换为String
类型。
else if (value instanceof TypedStringValue) {
// Convert value to target type here.
TypedStringValue typedStringValue = (TypedStringValue) value;
/**
* 此处可以解析SpEL表达式,见5.2.2.1
*/
Object valueObject = evaluate(typedStringValue);
try {
//获取目标类型,xml中配置的字符串则为null,见5.2.2.2
Class<?> resolvedTargetType = resolveTargetType(typedStringValue);
//指定了目标类型,直接进行转换
if (resolvedTargetType != null) {
return this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType);
}
/**
* 对于xml中配置的字符串则走这一个分支,因为现在根本不知道赋值的属性的类型
*/
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);
}
}
5.2.2.1 解析SpEL
表达式
/**
* Evaluate the given value as an expression, if necessary.
* @param value the candidate value (may be an expression)
* @return the resolved value
* 解析SpEL表达式
*/
@Nullable
protected Object evaluate(TypedStringValue value) {
//先获取TypedStringValue中保存的字符串,然后解析字符串中的表达式
Object result = doEvaluate(value.getValue());
if (!ObjectUtils.nullSafeEquals(result, value.getValue())) {
value.setDynamic();
}
return result;
}
/**
* Evaluate the given String value as an expression, if necessary.
* @param value the original value (may be an expression)
* @return the resolved value if necessary, or the original String value
*/
@Nullable
private Object doEvaluate(@Nullable String value) {
//最终使用工厂来解析value
return this.beanFactory.evaluateBeanDefinitionString(value, this.beanDefinition);
}
进入evaluateBeanDefinitionString
方法
/**
* Evaluate the given String as contained in a bean definition,
* potentially resolving it as an expression.
* @param value the value to check
* @param beanDefinition the bean definition that the value comes from
* @return the resolved value
* @see #setBeanExpressionResolver
*/
@Nullable
protected Object evaluateBeanDefinitionString(@Nullable String value, @Nullable BeanDefinition beanDefinition) {
//工厂中没有表达式解析器就直接返回
if (this.beanExpressionResolver == null) {
return value;
}
//当前bean的作用域对象
Scope scope = null;
if (beanDefinition != null) {
String scopeName = beanDefinition.getScope();
if (scopeName != null) {
scope = getRegisteredScope(scopeName);
}
}
/**
* spring自动的向工厂中放入了一个StandardBeanExpressionResolver,即解析我们常用的SpEL表达式
*/
return this.beanExpressionResolver.evaluate(value, new BeanExpressionContext(this, scope));
}
5.2.2.2 解析字符串的目标类型
/**
* Resolve the target type in the given TypedStringValue.
* @param value the TypedStringValue to resolve
* @return the resolved target type (or {@code null} if none specified)
* @throws ClassNotFoundException if the specified type cannot be resolved
* @see TypedStringValue#resolveTargetType
*/
@Nullable
protected Class<?> resolveTargetType(TypedStringValue value) throws ClassNotFoundException {
//先从缓存中得到目标类型
if (value.hasTargetType()) {
return value.getTargetType();
}
//解析目标类型
return value.resolveTargetType(this.beanFactory.getBeanClassLoader());
}
得到
TypedStringValue
中定义的目标类型
//目标类型,可能是clazz对象或者类的完全限定名
@Nullable
private volatile Object targetType;
/**
* Determine the type to convert to, resolving it from a specified class name
* if necessary. Will also reload a specified Class from its name when called
* with the target type already resolved.
* @param classLoader the ClassLoader to use for resolving a (potential) class name
* @return the resolved type to convert to
* @throws ClassNotFoundException if the type cannot be resolved
*/
@Nullable
public Class<?> resolveTargetType(@Nullable ClassLoader classLoader) throws ClassNotFoundException {
//得到目标类型的完全限定名
String typeName = getTargetTypeName();
if (typeName == null) {
return null;
}
//反射加载得到目标类型的clazz对象
Class<?> resolvedClass = ClassUtils.forName(typeName, classLoader);
//缓存
this.targetType = resolvedClass;
return resolvedClass;
}
/**
* Return the type to convert to.
*/
@Nullable
public String getTargetTypeName() {
Object targetTypeValue = this.targetType;
if (targetTypeValue instanceof Class) {
return ((Class<?>) targetTypeValue).getName();
}
else {
return (String) targetTypeValue;
}
}
对于在
XML
文件中配置的value=String
字符串,它的目标类型为null
,因为你在配置的时候没有手动指定,并且字符串的目标类型应该和你要填充的属性类型是相同的,必须要通过反射解析setter
方法的参数类型,才能得到字符串要转换的类型。