spring的类型转换基本上是在TypeConverterDelegate来完成的,其首先是利用PropertyEditor来进行转换的,这个接口是在java.beans中定义的,主要是在GUI上操作的,其主要的转换方式是String类型与其他类型的转换。
由于PropertyEditor的局限性,spring自己定义了一套类型转换器,这个类型转换器是定义在spring-core包下,对外接口主要是ConversionService来进行类型转换,
而ConversionService则是将类型转换委托给注册进来的Converter,GenericConverter,ConverterFactory来进行具体的操作
不过这些注册方式是进行对象的类型转换,即将字符串转换为boolean,int,集合这些类型的转换,但是对应RuntimeBeanReference这些需要借助beanFactory来获取对应的转换对象,而Converter,PropertyEditor都是外部的公共转换器,所以其对应的转换操作不是在这里实现的,其对应的实现逻辑是在BeanDefinitionValueResolver中。
Converter中只定义了一个convert() 不过它定义了两个泛型即S,T表示source和target,它注入到ConvertionServie则是借助ConverterAdapter对ConditionalGenericConverter进行适配注册的,其最终是通过获取子类这两个泛型的具体类型组成ConvertiblePair对作为key注册的。
可以看到这个Converter的转换主要是对简单类型进行转换,即source和target都是不带泛型的
public interface Converter<S, T> {
T convert(S source);
}
GenericConverter提供了两个方法。一个getConvertibleTypes(…) 主要是获取其可以进行转化的sourceType,targetType的转化对。
另一个则是converter(…) 这个方法,不过这个方法的sourceType和targetType都是TypeDescriptor , 这个TypeDescriptor 中除了维护对应的class,还维护了对应的ResolvableType这个泛型。
可以看到GenericConverter的实现大部分是collection,array,map这些带有泛型的类型转换
public interface GenericConverter {
//注册到Converters则是通过获取这写ConvertiblePair作为key存储到map中
Set<ConvertiblePair> getConvertibleTypes();
Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
final class ConvertiblePair {
private final Class<?> sourceType;
private final Class<?> targetType;
...
}
}
提供一个maches方法,主要是用来匹配对应的类型能否进行类型转换
public interface ConditionalConverter {
boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType);
}
ConditionalGenericConverter 继承了GenericConverter和ConditionalConverter
public interface ConditionalGenericConverter extends GenericConverter, ConditionalConverter {
}
ConverterFactory是另一种类型的转换器,它主要是根据目标类型生成一个Converter来进行转换,主要是对Number,Enum这种需要依赖目标类的转换来进行操作的转换实现。
public interface ConverterFactory<S, R> {
<T extends R> Converter<S, T> getConverter(Class<T> targetType);
}
ConversionServie 是spring用来进行类型转化的一类接口,它主要定义了canConverter(…) 和converter(…) 两类方法
public interface ConversionService {
boolean canConvert(Class<?> sourceType, Class<?> targetType);
boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType);
<T> T convert(Object source, Class<T> targetType);
Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
}
ConverterRegistry 是converter的注册器,其主要是注册Converter,GenericConerter和ConerterFactory三种类型的转化器
public interface ConverterRegistry {
void addConverter(Converter<?, ?> converter);
<S, T> void addConverter(Class<S> sourceType, Class<T> targetType, Converter<? super S, ? extends T> converter);
void addConverter(GenericConverter converter);
void addConverterFactory(ConverterFactory<?, ?> factory);
void removeConvertible(Class<?> sourceType, Class<?> targetType);
}
这个接口继承ConversionService和ConversionService,表示其有注册Converter和进行转化的功能。
public interface ConfigurableConversionService extends ConversionService, ConverterRegistry {
}
GenericConvertionService 的逻辑是利用Converters维护所有的GenericConverter,并利用converterCache这个map存储从Converters中利用sourceType和targetType查询的对应的GenericConverter的缓存。
对于Convter和ConverterFactory,则是利用为ConverterAdapter和ConverterFactoryAdapter这两个适配器转换为GenericConvter来进行注册
public class GenericConversionService implements ConfigurableConversionService {
//主要维护GenericConverter
private final Converters converters = new Converters();
//用sourceType和targetType来生成一个key做查找缓存
private final Map<ConverterCacheKey, GenericConverter> converterCache =
new ConcurrentReferenceHashMap<ConverterCacheKey, GenericConverter>(64);
@Override
public void addConverter(Converter<?, ?> converter) {
//这里是将converter的两个泛型转换为两个ResolvableType
ResolvableType[] typeInfo = getRequiredTypeInfo(converter.getClass(), Converter.class);
//经过spring代理的对象都会实现DecoratingProxy接口并且代理的target的class是从getDecoratedClass获取
if (typeInfo == null && converter instanceof DecoratingProxy) {
typeInfo = getRequiredTypeInfo(((DecoratingProxy) converter).getDecoratedClass(), Converter.class);
}
if (typeInfo == null) {
...
}
//利用ConverterAdapter将Converter转换为GenericConverter注册到ConvertionService
addConverter(new ConverterAdapter(converter, typeInfo[0], typeInfo[1]));
}
@Override
public void addConverter(GenericConverter converter) {
//Converters加入GenericConverter
this.converters.add(converter);
//将converterCache中的缓存都清理掉
invalidateCache();
}
@Override
public void addConverterFactory(ConverterFactory<?, ?> factory) {
ResolvableType[] typeInfo = getRequiredTypeInfo(factory.getClass(), ConverterFactory.class);
if (typeInfo == null && factory instanceof DecoratingProxy) {
typeInfo = getRequiredTypeInfo(((DecoratingProxy) factory).getDecoratedClass(), ConverterFactory.class);
}
if (typeInfo == null) {
...
}
addConverter(new ConverterFactoryAdapter(factory,
new ConvertiblePair(typeInfo[0].resolve(), typeInfo[1].resolve())));
}
//canConverter主要是看利用sourceType和targetType能否获取对应的GenericConverter进行转换
@Override
public boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType) {
if (sourceType == null) {
return true;
}
GenericConverter converter = getConverter(sourceType, targetType);
return (converter != null);
}
@Override
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (sourceType == null) {
return handleResult(null, targetType, convertNullSource(null, targetType));
}
if (source != null && !sourceType.getObjectType().isInstance(source)) {
...
}
GenericConverter converter = getConverter(sourceType, targetType);
if (converter != null) {
//调用converter#convert方法
Object result = ConversionUtils.invokeConverter(converter, source, sourceType, targetType);
//主要是检查一下result是null的时候其对应的targetType不应该是int,long这些简单类
return handleResult(sourceType, targetType, result);
}
//如果source能直接转换为targetType则直接返回source,否则抛异常
return handleConverterNotFound(source, sourceType, targetType);
}
}
Converters是一个容器,主要是存储了GenericConvter,它主要维护了两个属性,
利用soruceType,targetType从Converters找对应的GenericConverter的主要步骤是将soueceType和targetType的所有的父类和父接口组合成ConvertiblePair从converts这个map中找对应的GenericConverter,没找到则遍历globalConverters 进行查找。
private static class Converters {
private final Set<GenericConverter> globalConverters = new LinkedHashSet<GenericConverter>();
//ConvertersForPair其实就是一个List,每次利用sourceType,targetType找对应的GenericConverter都是找sourceType和targetType的所有实现的接口和父类组成的所有中类型的ConvertiblePair对应的ConvertersForPair,然后遍历ConvertersForPair知道match方法匹配的GenericConverter
private final Map<ConvertiblePair, ConvertersForPair> converters =
new LinkedHashMap<ConvertiblePair, ConvertersForPair>(36);
}
TypeConverterDelegate是spring类型转换的最终的逻辑所在,不过不知道是历史原因还是设计原因,个人感觉这段代码看起来的感觉就是乱,当然主要操作是利用PropertyEditor和ConversionService进行转换,在它们没有转换成功时,这个类也进行了一些类型转换。
对于本地做了集合类型的转换个人认为的原因是集合的内部类型的转换可能在ConvertionService内部需要PropertyEditor来完成转换,在ConvertionService无法独立完成操作,所以在此进行操作,反之也是这样。但是对于Number,Enum这些的转换在此处进行操作有些不太理解,完全可以扩展Converter或者PropertyEditor进行操作。
class TypeConverterDelegate {
private final PropertyEditorRegistrySupport propertyEditorRegistry;
private final Object targetObject;
public <T> T convertIfNecessary(String propertyName, Object oldValue, Object newValue,
Class<T> requiredType, TypeDescriptor typeDescriptor) throws IllegalArgumentException {
PropertyEditor editor = this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName);
ConversionFailedException conversionAttemptEx = null;
ConversionService conversionService = this.propertyEditorRegistry.getConversionService();
//editor是空的,并且有ConversionService的条件则利用ConversionService进行转换
if (editor == null && conversionService != null && newValue != null && typeDescriptor != null) {
TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue);
if (conversionService.canConvert(sourceTypeDesc, typeDescriptor)) {
try {
return (T) conversionService.convert(newValue, sourceTypeDesc, typeDescriptor);
}
catch (ConversionFailedException ex) {
conversionAttemptEx = ex;
}
}
}
Object convertedValue = newValue;
//尝试用PropertyEditor进行转换
if (editor != null || (requiredType != null && !ClassUtils.isAssignableValue(requiredType, convertedValue))) {
//这一段操作不知道原因
if (typeDescriptor != null && requiredType != null && Collection.class.isAssignableFrom(requiredType) &&
convertedValue instanceof String) {
TypeDescriptor elementTypeDesc = typeDescriptor.getElementTypeDescriptor();
if (elementTypeDesc != null) {
Class<?> elementType = elementTypeDesc.getType();
if (Class.class == elementType || Enum.class.isAssignableFrom(elementType)) {
convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
}
}
}
if (editor == null) {
//从PropertyEditorRegistrySupport中获取默认的PropertyEditor
editor = findDefaultEditor(requiredType);
}
//利用PropertyEditor进行类型转换(注意:这里的PropertyEditor可能是公用的,而没个PropertyEditor中其实维护了一个value,所以每次用string转换为对应类型时,都会将oldValue放入PropertyEditor中)
convertedValue = doConvertValue(oldValue, convertedValue, requiredType, editor);
}
boolean standardConversion = false;
if (requiredType != null) {
if (convertedValue != null) {
if (Object.class == requiredType) {
return (T) convertedValue;
}
else if (requiredType.isArray()) {
//对于枚举,如果是字符串则将这个字符串以,展开
if (convertedValue instanceof String && Enum.class.isAssignableFrom(requiredType.getComponentType())) {
convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
}
return (T) convertToTypedArray(convertedValue, propertyName, requiredType.getComponentType());
}
//collection之间转换
else if (convertedValue instanceof Collection) {
convertedValue = convertToTypedCollection(
(Collection<?>) convertedValue, propertyName, requiredType, typeDescriptor);
standardConversion = true;
}
//map之间转换
else if (convertedValue instanceof Map) {
convertedValue = convertToTypedMap(
(Map<?, ?>) convertedValue, propertyName, requiredType, typeDescriptor);
standardConversion = true;
}
if (convertedValue.getClass().isArray() && Array.getLength(convertedValue) == 1) {
convertedValue = Array.get(convertedValue, 0);
standardConversion = true;
}
if (String.class == requiredType && ClassUtils.isPrimitiveOrWrapper(convertedValue.getClass())) {
// We can stringify any primitive value...
return (T) convertedValue.toString();
}
else if (convertedValue instanceof String && !requiredType.isInstance(convertedValue)) {
//convertedValue如果是字符串的话则直接用这个字符串作为参数实例化这个类作为返回值
if (conversionAttemptEx == null && !requiredType.isInterface() && !requiredType.isEnum()) {
try {
Constructor<T> strCtor = requiredType.getConstructor(String.class);
return BeanUtils.instantiateClass(strCtor, convertedValue);
}
catch (NoSuchMethodException ex) {
...
}
catch (Exception ex) {
...
}
}
String trimmedValue = ((String) convertedValue).trim();
if (requiredType.isEnum() && trimmedValue.isEmpty()) {
// It's an empty enum identifier: reset the enum value to null.
return null;
}
//尝试转换为enum
convertedValue = attemptToConvertStringToEnum(requiredType, trimmedValue, convertedValue);
standardConversion = true;
}
//尝试转换为number
else if (convertedValue instanceof Number && Number.class.isAssignableFrom(requiredType)) {
convertedValue = NumberUtils.convertNumberToTargetClass(
(Number) convertedValue, (Class<Number>) requiredType);
standardConversion = true;
}
}
else {
if (javaUtilOptionalEmpty != null && requiredType == javaUtilOptionalEmpty.getClass()) {
convertedValue = javaUtilOptionalEmpty;
}
}
if (!ClassUtils.isAssignableValue(requiredType, convertedValue)) {
if (conversionAttemptEx != null) {
throw conversionAttemptEx;
}
//前面conversionService没进行操作,再利用conversionService进行一次操作
else if (conversionService != null) {
TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue);
if (conversionService.canConvert(sourceTypeDesc, typeDescriptor)) {
return (T) conversionService.convert(newValue, sourceTypeDesc, typeDescriptor);
}
}
...
}
}
if (conversionAttemptEx != null) {
if (editor == null && !standardConversion && requiredType != null && Object.class != requiredType) {
throw conversionAttemptEx;
}
}
return (T) convertedValue;
}
}
BeanDefinitionValueResolver主要是对beanFactory的相应的reference的操作,其主要是利用给的beanName从beanFactory中获取对应的bean。
其操作主要是对配置中的几个参数进行处理,其主要操作是evaluate和从beanFactory中获取对应的bean以及利用beanDefinition创建对应的bean三种方式进行类型转换操作。其中evalueate的主要是利用BeanExpressionResolver进行表达式的计算(即#{1+2}这种类型的字符串的计算),另一种则是RuntimeBeanReference这种通过对应的beanName从beanFactory中获取对应的bean。而BeanDefinition则是直接利用beanDefinition用beanFactory创建对应的bean。
注意:这里的利用BeanDefinition的方式创建的bean没有注册进入beanFactory中。只是利用beanFactory创建了对应的bean
对于ManagedArray,ManagedList等集合都是对其内部的对应的数据递归调用resolveValueIfNecessary并将结果放入集合中。
public Object resolveValueIfNecessary(Object argName, Object value) {
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
}
return refName;
}
else if (value instanceof BeanDefinitionHolder) {
BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value;
return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());
}
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);
}
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
}
}
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);
}
else if (value instanceof ManagedMap) {
// May need to resolve contained runtime references.
return resolveManagedMap(argName, (Map<?, ?>) value);
}
//注意这里的properties是不能设置ref这种bean的方式
else if (value instanceof ManagedProperties) {
Properties original = (Properties) value;
Properties copy = new Properties();
for (Map.Entry<Object, Object> propEntry : original.entrySet()) {
Object propKey = propEntry.getKey();
Object propValue = propEntry.getValue();
if (propKey instanceof TypedStringValue) {
propKey = evaluate((TypedStringValue) propKey);
}
if (propValue instanceof TypedStringValue) {
propValue = evaluate((TypedStringValue) propValue);
}
copy.put(propKey, propValue);
}
return copy;
}
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
}
}
else {
return evaluate(value);
}
}
下面的配置展示了上面的各个类型的配置
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<bean class="com.test.springbean.bean2.TestRefrence">
<!-- RuntimeBeanNameReference -->
<property name="a"><idref bean="ref1"></idref></property>
<property name="b">
<!-- ManagedArray -->
<array value-type="com.test.springbean.bean2.Reference">
<!-- RuntimeBeanReference -->
<ref bean="ref2" />
</array>
</property>
<property name="c">
<!-- ManagedList -->
<list value-type="com.test.springbean.bean2.Reference">
<ref bean="ref3" />
<!-- BeanDefinitionHolder -->
<bean class="com.test.springbean.bean2.Reference" name="ref5"><property name="id" value="5"/></bean>
</list>
</property>
<!-- ManagedSet -->
<property name="d">
<set value-type="com.test.springbean.bean2.Reference">
<ref bean="ref7" />
<bean class="com.test.springbean.bean2.Reference" name="ref9"><property name="id" value="9"/></bean>
</set>
</property>
<!-- ManagedMap -->
<property name="e">
<map key-type="com.test.springbean.bean2.Reference" value-type="com.test.springbean.bean2.Reference">
<entry key-ref="ref10" value-ref="ref11"/>
</map>
</property>
<!-- TypedStringValue -->
<property name="f"><value type="java.lang.Integer">#{1+2}</value></property>
<!-- ManagedProperties -->
<property name="g">
<props>
<prop key="key">value</prop>
</props>
</property>
</bean>
<bean class="com.test.springbean.bean2.Reference" name="ref1"><property name="id" value="1"/></bean>
<bean class="com.test.springbean.bean2.Reference" name="ref2"><property name="id" value="2"/></bean>
<bean class="com.test.springbean.bean2.Reference" name="ref3"><property name="id" value="3"/></bean>
<bean class="com.test.springbean.bean2.Reference" name="ref7"><property name="id" value="7"/></bean>
<bean class="com.test.springbean.bean2.Reference" name="ref10"><property name="id" value="10"/></bean>
<bean class="com.test.springbean.bean2.Reference" name="ref11"><property name="id" value="11"/></bean>
</beans>