IT@程序员猿媛

【Spring 笔记】Bean 的类型转换相关整理

2020-01-13  本文已影响0人  58bc06151329

文前说明

作为码农中的一员,需要不断的学习,我工作之余将一些分析总结和学习笔记写成博客与大家一起交流,也希望采用这种方式记录自己的学习之旅。

本文仅供学习交流使用,侵权必删。
不用于商业目的,转载请注明出处。

1. 概述

2. 原理

// AbstractAutowireCapableBeanFactory.java#populateBean
// bean 的属性值
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
......
// 将属性应用到 bean 中
if (pvs != null) {
    applyPropertyValues(beanName, mbd, bw, pvs);
}

// AbstractAutowireCapableBeanFactory.java#applyPropertyValues
// 遍历属性,将属性转换为对应类的对应属性的类型
    for (PropertyValue pv : original) {
        // 属性值不需要转换
        if (pv.isConverted()) {
            deepCopy.add(pv);
        // 属性值需要转换
        } else {
            String propertyName = pv.getName();
            Object originalValue = pv.getValue(); // 原始的属性值,即转换之前的属性值
            Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue); // 转换属性值,例如将引用转换为IoC容器中实例化对象引用 !!!!! 对属性值的解析!!
            Object convertedValue = resolvedValue; // 转换之后的属性值
            boolean convertible = bw.isWritableProperty(propertyName) &&
                    !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);  // 属性值是否可以转换
            // 使用用户自定义的类型转换器转换属性值
            if (convertible) {
                convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
            }
......
// AbstractAutowireCapableBeanFactory。java
@Nullable
private Object convertForProperty(
        @Nullable Object value, String propertyName, BeanWrapper bw, TypeConverter converter) {
    // 若 TypeConverter 为 BeanWrapperImpl 类型,则使用 BeanWrapperImpl 进行类型转换,BeanWrapperImpl 实现了 PropertyEditorRegistry 接口。
    if (converter instanceof BeanWrapperImpl) {
        return ((BeanWrapperImpl) converter).convertForProperty(value, propertyName);
    } else {
        // 获得属性对应的 PropertyDescriptor 对象
        PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
        // 获得属性对应的 setting MethodParameter 对象
        MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
        // 执行转换
        return converter.convertIfNecessary(value, pd.getPropertyType(), methodParam);
    }
}
// TypeConverterSupport.java
@Override
@Nullable
public <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType, @Nullable Field field)
        throws TypeMismatchException {
    return doConvert(value, requiredType, null, field);
}

@Nullable
private <T> T doConvert(@Nullable Object value,@Nullable Class<T> requiredType,
        @Nullable MethodParameter methodParam, @Nullable Field field) throws TypeMismatchException {
    Assert.state(this.typeConverterDelegate != null, "No TypeConverterDelegate");
    try {
        if (field != null) { // field
            return this.typeConverterDelegate.convertIfNecessary(value, requiredType, field);
        } else { // methodParam
            return this.typeConverterDelegate.convertIfNecessary(value, requiredType, methodParam);
        }
    } catch (ConverterNotFoundException | IllegalStateException ex) {
        throw new ConversionNotSupportedException(value, requiredType, ex);
    } catch (ConversionException | IllegalArgumentException ex) {
        throw new TypeMismatchException(value, requiredType, ex);
    }
}
// TypeConverterDelegate.java
@Nullable
public <T> T convertIfNecessary(@Nullable String propertyName, @Nullable Object oldValue, @Nullable Object newValue,
        @Nullable Class<T> requiredType, @Nullable TypeDescriptor typeDescriptor) throws IllegalArgumentException {
        ......
        // No custom editor but custom ConversionService specified?
        ConversionService conversionService = this.propertyEditorRegistry.getConversionService();
        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) {
                    // fallback to default conversion logic below
                    conversionAttemptEx = ex;
                }
            }
        }
       ......
}
// ConversionService.java
public interface ConversionService {

    boolean canConvert(@Nullable Class<?> sourceType, Class<?> targetType);

    boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType);

    @Nullable
    <T> T convert(@Nullable Object source, Class<T> targetType);

    @Nullable
    Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType);

}
ConversionService 类型转换体系

convert

// ConversionService.java
Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType);
参数 说明
source 要转换的源对象,可以为 null 。
sourceType source 的类型的上下文,如果 source 为 null ,则可以为 null 。
targetType source 要转换的类型的上下文。
// GenericConversionService.java
@Override
@Nullable
public Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
    Assert.notNull(targetType, "Target type to convert to cannot be null");
    // 1. 如果 sourceType 为空,则直接处理结果
    if (sourceType == null) {
        Assert.isTrue(source == null, "Source must be [null] if source type == [null]");
        return handleResult(null, targetType, convertNullSource(null, targetType));
    }
    // 2. 如果类型不对,抛出 IllegalArgumentException 异常
    if (source != null && !sourceType.getObjectType().isInstance(source)) {
        throw new IllegalArgumentException("Source to convert from must be an instance of [" +
                sourceType + "]; instead it was a [" + source.getClass().getName() + "]");
    }
    // 3. 获得对应的 GenericConverter 对象
    GenericConverter converter = getConverter(sourceType, targetType);
    // 4. 如果 converter 非空,则进行转换,然后再处理结果
    if (converter != null) {
        // 4.1. 执行转换
        Object result = ConversionUtils.invokeConverter(converter, source, sourceType, targetType);
        // 4.2. 处理器结果
        return handleResult(sourceType, targetType, result);
    }
    // 5. 处理 converter 为空的情况
    return handleConverterNotFound(source, sourceType, targetType);
}
// ConversionUtils.java
@Nullable
public static Object invokeConverter(GenericConverter converter, @Nullable Object source,
        TypeDescriptor sourceType, TypeDescriptor targetType) {
    try {
        // 执行转换
        return converter.convert(source, sourceType, targetType);
    } catch (ConversionFailedException ex) {
        throw ex;
    } catch (Throwable ex) {
        throw new ConversionFailedException(sourceType, targetType, source, ex);
    }
}
// GenericConversionService.java
@Nullable
private Object handleResult(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType, @Nullable Object result) {
    if (result == null) {
        assertNotPrimitiveTargetType(sourceType, targetType);
    }
    return result;
}

private void assertNotPrimitiveTargetType(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
    if (targetType.isPrimitive()) {
        throw new ConversionFailedException(sourceType, targetType, null,
                new IllegalArgumentException("A null value cannot be assigned to a primitive type"));
    }
}
// GenericConversionService.java
@Nullable
private Object handleConverterNotFound(
        @Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
    // 1. 如果 source 为空,则返回空
    if (source == null) {
        assertNotPrimitiveTargetType(sourceType, targetType);
        return null;
    }
    // 2. 如果 sourceType 为空,或者 targetType 是 sourceType 的子类,则返回 source
    if ((sourceType == null || sourceType.isAssignableTo(targetType)) &&
            targetType.getObjectType().isInstance(source)) {
        return source;
    }
    // 3. 抛出 ConverterNotFoundException 异常
    throw new ConverterNotFoundException(sourceType, targetType);
}

getConverter

// GenericConversionService.java
@Nullable
protected GenericConverter getConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {
    // 创建 ConverterCacheKey 对象
    ConverterCacheKey key = new ConverterCacheKey(sourceType, targetType);
    // 从 converterCache 缓存中,获得 GenericConverter 对象 converter
    GenericConverter converter = this.converterCache.get(key);
    // 如果获得到,则返回 converter
    if (converter != null) {
        return (converter != NO_MATCH ? converter : null);
    }

    // 如果获取不到,则从 converters 中查找
    converter = this.converters.find(sourceType, targetType);
    // 如果查找不到,则获得默认的 Converter 对象
    if (converter == null) {
        converter = getDefaultConverter(sourceType, targetType);
    }

    // 如果找到 converter ,则添加 converter 到 converterCache 中,并返回 converter
    if (converter != null) {
        this.converterCache.put(key, converter);
        return converter;
    }

    // 如果找不到 converter ,则添加 NO_MATCH 占位符到 converterCache 中,并返回 null
    this.converterCache.put(key, NO_MATCH);
    return null;
}
// GenericConversionService.java#Converters
private final Set<GenericConverter> globalConverters = new LinkedHashSet<>();

private final Map<ConvertiblePair, ConvertersForPair> converters = new LinkedHashMap<>(36);
// GenericConversionService.java#Converters
@Nullable
public GenericConverter find(TypeDescriptor sourceType, TypeDescriptor targetType) {
    // Search the full type hierarchy
    List<Class<?>> sourceCandidates = getClassHierarchy(sourceType.getType());
    List<Class<?>> targetCandidates = getClassHierarchy(targetType.getType());
    // 遍历 sourceCandidates 数组
    for (Class<?> sourceCandidate : sourceCandidates) {
        // 遍历 targetCandidates 数组
        for (Class<?> targetCandidate : targetCandidates) {
            // 创建 ConvertiblePair 对象
            ConvertiblePair convertiblePair = new ConvertiblePair(sourceCandidate, targetCandidate);
            // 获得 GenericConverter 对象
            GenericConverter converter = getRegisteredConverter(sourceType, targetType, convertiblePair);
            if (converter != null) {
                return converter;
            }
        }
    }
    return null;
}

@Nullable
private GenericConverter getRegisteredConverter(TypeDescriptor sourceType,
        TypeDescriptor targetType, ConvertiblePair convertiblePair) {
    // Check specifically registered converters
    // 从 converters 中,获得 converter
    ConvertersForPair convertersForPair = this.converters.get(convertiblePair);
    if (convertersForPair != null) {
        GenericConverter converter = convertersForPair.getConverter(sourceType, targetType);
        if (converter != null) {
            return converter;
        }
    }
    // Check ConditionalConverters for a dynamic match
    // 从 globalConverters 中,获得 globalConverter
    for (GenericConverter globalConverter : this.globalConverters) {
        if (((ConditionalConverter) globalConverter).matches(sourceType, targetType)) {
            return globalConverter;
        }
    }
    return null;
}
// GenericConverter.java
Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType);

2.1 类型转换器

GenericConverter

// GenericConverter.java
public interface GenericConverter {

    @Nullable
    Set<ConvertiblePair> getConvertibleTypes();

    @Nullable
    Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType);

}
// StringToArrayConverter.java
final class StringToArrayConverter implements ConditionalGenericConverter {

    private final ConversionService conversionService;

    public StringToArrayConverter(ConversionService conversionService) {
        this.conversionService = conversionService;
    }

    @Override
    public Set<ConvertiblePair> getConvertibleTypes() {
        return Collections.singleton(new ConvertiblePair(String.class, Object[].class));
    }

    @Override
    public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
        return ConversionUtils.canConvertElements(sourceType, targetType.getElementTypeDescriptor(),
                this.conversionService);
    }

    @Override
    @Nullable
    public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
        if (source == null) {
            return null;
        }
        // 按照 , 分隔成字符串数组
        String string = (String) source;
        String[] fields = StringUtils.commaDelimitedListToStringArray(string);
        // 获得 TypeDescriptor 对象
        TypeDescriptor targetElementType = targetType.getElementTypeDescriptor();
        Assert.state(targetElementType != null, "No target element type");
        // 创建目标数组
        Object target = Array.newInstance(targetElementType.getType(), fields.length);
        // 遍历 fields 数组,逐个转换
        for (int i = 0; i < fields.length; i++) {
            String sourceElement = fields[i];
            // 执行转换
            Object targetElement = this.conversionService.convert(sourceElement.trim(), sourceType, targetElementType);
            // 设置到 target 中
            Array.set(target, i, targetElement);
        }
        return target;
    }

}

Converter

// Converter.java
public interface Converter<S, T> {

    @Nullable
    T convert(S source);

}
public static void registerConverters(ConverterRegistry registry) {
    DateFormatterRegistrar.addDateConverters(registry);
    registry.addConverter(new DateTimeConverters.LocalDateTimeToLocalDateConverter());
    registry.addConverter(new DateTimeConverters.LocalDateTimeToLocalTimeConverter());
    registry.addConverter(new DateTimeConverters.ZonedDateTimeToLocalDateConverter());
    registry.addConverter(new DateTimeConverters.ZonedDateTimeToLocalTimeConverter());
    registry.addConverter(new DateTimeConverters.ZonedDateTimeToLocalDateTimeConverter());
    registry.addConverter(new DateTimeConverters.ZonedDateTimeToOffsetDateTimeConverter());
    registry.addConverter(new DateTimeConverters.ZonedDateTimeToInstantConverter());
    registry.addConverter(new DateTimeConverters.OffsetDateTimeToLocalDateConverter());
    registry.addConverter(new DateTimeConverters.OffsetDateTimeToLocalTimeConverter());
    registry.addConverter(new DateTimeConverters.OffsetDateTimeToLocalDateTimeConverter());
    registry.addConverter(new DateTimeConverters.OffsetDateTimeToZonedDateTimeConverter());
    registry.addConverter(new DateTimeConverters.OffsetDateTimeToInstantConverter());
    registry.addConverter(new DateTimeConverters.CalendarToZonedDateTimeConverter());
    registry.addConverter(new DateTimeConverters.CalendarToOffsetDateTimeConverter());
    registry.addConverter(new DateTimeConverters.CalendarToLocalDateConverter());
    registry.addConverter(new DateTimeConverters.CalendarToLocalTimeConverter());
    registry.addConverter(new DateTimeConverters.CalendarToLocalDateTimeConverter());
    registry.addConverter(new DateTimeConverters.CalendarToInstantConverter());
    registry.addConverter(new DateTimeConverters.LongToInstantConverter());
    registry.addConverter(new DateTimeConverters.InstantToLongConverter());
}

ConditionalConverter

// ConditionalConverter.java
public interface ConditionalConverter {

    boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType);

}

ConverterFactory

// ConverterFactory.java
public interface ConverterFactory<S, R> {

    <T extends R> Converter<S, T> getConverter(Class<T> targetType);

}

2.2 GenericConversionService

// GenericConversionService.java
@Override
public void addConverter(Converter<?, ?> converter) {
    // 1. 获取 ResolvableType 对象,基于 converter.getClass() 类
    ResolvableType[] typeInfo = getRequiredTypeInfo(converter.getClass(), Converter.class);
    // 1. 如果获取不到,并且 converter 是 DecoratingProxy 类型,则基于 ((DecoratingProxy) converter).getDecoratedClass() 类
    if (typeInfo == null && converter instanceof DecoratingProxy) {
        typeInfo = getRequiredTypeInfo(((DecoratingProxy) converter).getDecoratedClass(), Converter.class);
    }
    // 如果获取不到,抛出 IllegalArgumentException 异常
    if (typeInfo == null) {
        throw new IllegalArgumentException("Unable to determine source type <S> and target type <T> for your " +
                "Converter [" + converter.getClass().getName() + "]; does the class parameterize those types?");
    }
    // 2. 封装成 ConverterAdapter 对象,添加到 converters 中
    addConverter(new ConverterAdapter(converter, typeInfo[0], typeInfo[1]));
}

addConverter

// GenericConversionService.java
@Override
public void addConverter(GenericConverter converter) {
    // 添加到 converters 中
    this.converters.add(converter);
    // 过期缓存
    invalidateCache();
}
// GenericConversionService.java
public void add(GenericConverter converter) {
    // 1. 获得 ConvertiblePair 集合
    Set<ConvertiblePair> convertibleTypes = converter.getConvertibleTypes();
    // 2. 如果为空,并且 converter 是 ConditionalConverter 类型,则添加到 globalConverters 中
    if (convertibleTypes == null) {
        Assert.state(converter instanceof ConditionalConverter,
                "Only conditional converters may return null convertible types");
        this.globalConverters.add(converter);
    } else {
        // 3. 通过迭代的方式依次添加 converters 中
        for (ConvertiblePair convertiblePair : convertibleTypes) {
            // 从 converters 中,获得 ConvertersForPair 对象
            ConvertersForPair convertersForPair = getMatchableConverters(convertiblePair);
            // 添加 converter 到 ConvertersForPair 中
            convertersForPair.add(converter);
        }
    }
}
// GenericConverter.java#ConvertiblePair
final class ConvertiblePair {

    private final Class<?> sourceType;
    private final Class<?> targetType;
    ......
}
// GenericConversionService.java#ConvertersForPair
private static class ConvertersForPair {

   private final LinkedList<GenericConverter> converters = new LinkedList<>();

    public void add(GenericConverter converter) {
        this.converters.addFirst(converter);
    }

    @Nullable
    public GenericConverter getConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {
        for (GenericConverter converter : this.converters) {
            if (!(converter instanceof ConditionalGenericConverter) ||
                    ((ConditionalGenericConverter) converter).matches(sourceType, targetType)) {
                return converter;
            }
        }
        return null;
    }

}

2.3 DefaultConversionService

// DefaultConversionService.java
public DefaultConversionService() {
    addDefaultConverters(this);
}

public static void addDefaultConverters(ConverterRegistry converterRegistry) {
    addScalarConverters(converterRegistry);
    addCollectionConverters(converterRegistry);

    converterRegistry.addConverter(new ByteBufferConverter((ConversionService) converterRegistry));
    converterRegistry.addConverter(new StringToTimeZoneConverter());
    converterRegistry.addConverter(new ZoneIdToTimeZoneConverter());
    converterRegistry.addConverter(new ZonedDateTimeToCalendarConverter());

    converterRegistry.addConverter(new ObjectToObjectConverter());
    converterRegistry.addConverter(new IdToEntityConverter((ConversionService) converterRegistry));
    converterRegistry.addConverter(new FallbackObjectToStringConverter());
    converterRegistry.addConverter(new ObjectToOptionalConverter((ConversionService) converterRegistry));
}

2.4 自定义类型转换器

// ConversionServiceFactoryBean.java
@Override
public void afterPropertiesSet() {
    // 1. 创建 DefaultConversionService 对象
    this.conversionService = createConversionService();
    // 2. 注册到 ConversionServiceFactory 中
    ConversionServiceFactory.registerConverters(this.converters, this.conversionService);
}
// ConversionServiceFactoryBean.java
protected GenericConversionService createConversionService() {
    return new DefaultConversionService();
}
// ConverterRegistry.java
public static void registerConverters(@Nullable Set<?> converters, ConverterRegistry registry) {
    if (converters != null) {
        // 遍历 converters 数组,逐个注册
        for (Object converter : converters) {
            if (converter instanceof GenericConverter) {
                registry.addConverter((GenericConverter) converter);
            } else if (converter instanceof Converter<?, ?>) {
                registry.addConverter((Converter<?, ?>) converter);
            } else if (converter instanceof ConverterFactory<?, ?>) {
                registry.addConverterFactory((ConverterFactory<?, ?>) converter);
            } else {
                throw new IllegalArgumentException("Each converter object must implement one of the " +
                        "Converter, ConverterFactory, or GenericConverter interfaces");
            }
        }
    }
}

配置

<?xml version="1.0" encoding="UTF-8"?>
<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.xsd">
    <bean id="conversionService"
          class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <ref bean="TestConversionService"/>
            </set>
        </property>
    </bean>
    <bean id="TestConversionService" class="TestConversionService"/>
    <bean id="test" class="Test">
        <property name="testObj" value="18#testObj"/>
    </bean>
</beans>

用例

//TestObj.java
public class TestObj {

    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

//TestConversionService.java
public class TestConversionService implements Converter<String, TestObj> {
    @Override
    public TestObj convert(String s) {
        if (StringUtils.hasLength(s)) {
            String[] sources = s.split("#");
            TestObj testObj = new TestObj();
            testObj.setAge(Integer.parseInt(sources[0]));
            testObj.setName(sources[1]);
            return testObj;
        }
        return null;
    }
}

//Test.java
public class Test {

    private TestObj testObj;

    public TestObj getTestObj() {
        return testObj;
    }

    public void setTestObj(TestObj testObj) {
        this.testObj = testObj;
    }

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        Test test = (Test) context.getBean("test");
        System.out.println("name:" + test.getTestObj().getName() + ",age:" + test.getTestObj().getAge());
    }
}

/* print
name:testObj,age:18
*/
上一篇 下一篇

猜你喜欢

热点阅读