Spring类型转换源码分析

前言

本文基于 spring 4.3.13 版本

在项目中我们经常使用 spring 提供的 IOC 功能,目前主要有两种方式:xml、注解,而这两种方式的原理是不同的,xml 的注入主要依赖 BeanWrapperImpl 进行属性注入,而注解是依赖 BeanPostProcessor 进行注入。在使用 IOC 功能的时候,经常需要利用 spring 提供的类型转换功能,比如 String -> IntegerString -> DateString -> Resource。那么 spring 又是如何实现的,我们来分析一波吧。

1、spring 杂货

1.1、ConfigurableBeanFactory

ConfigurableBeanFactory 是 BeanFactory 的子类,提供了包括支持类型转换功能的一系列配置接口,下面的代码列举了类型转换相关的接口。

public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry {

    void setConversionService(ConversionService conversionService);

    ConversionService getConversionService();

    void addPropertyEditorRegistrar(PropertyEditorRegistrar registrar);

    void registerCustomEditor(Class<?> requiredType, Class<? extends PropertyEditor> propertyEditorClass);

    void setTypeConverter(TypeConverter typeConverter);

    TypeConverter getTypeConverter();

    // other code......
}

其中 TypeConverter2.5+ 版本提供,默认使用 SimpleTypeConverter 实现,底层基于 jdk 提供的 PropertyEditor,只能实现 String 与 Object 的相互转换,由于 spring 创建 bean 的时候,配置信息大多是 String 类型,因此满足大部分的类型转换场景。但是这种弊端很明显,只能满足 String 与 Object 的相互转换,因此 spring3.x 引入了 Converter

1.2、TypeConverter 接口

TypeConverter 提供了类型转换的接口,提供了字段、方法参数的转换接口,接口定义如下所示:

package org.springframework.beans;

import java.lang.reflect.Field;
import org.springframework.core.MethodParameter;

public interface TypeConverter {

    <T> T convertIfNecessary(Object value, Class<T> requiredType) throws TypeMismatchException;

    <T> T convertIfNecessary(Object value, Class<T> requiredType, MethodParameter methodParam) throws TypeMismatchException;

    <T> T convertIfNecessary(Object value, Class<T> requiredType, Field field) throws TypeMismatchException;

}

spring 默认使用 SimpleTypeConverter 实现,继承关系如下图所示:

image

SimpleTypeConverter 继承至 PropertyEditorRegistrySupport,内置了几十种 java.beans.PropertyEditor (属性编辑器),部分代码如下所示。获取的时候,根据目标类型即可确定所需要的 PropertyEditor,例如:我需要注入 File 对象,那么根据 File.class 即可找到对应的 FileEditor

private void createDefaultEditors() {
    this.defaultEditors = new HashMap<Class<?>, PropertyEditor>(64);
    this.defaultEditors.put(Charset.class, new CharsetEditor());
    this.defaultEditors.put(Class.class, new ClassEditor());
    this.defaultEditors.put(Class[].class, new ClassArrayEditor());
    this.defaultEditors.put(Currency.class, new CurrencyEditor());
    this.defaultEditors.put(File.class, new FileEditor());
    this.defaultEditors.put(InputStream.class, new InputStreamEditor());
    this.defaultEditors.put(InputSource.class, new InputSourceEditor());
    this.defaultEditors.put(Locale.class, new LocaleEditor());
    if (pathClass != null) {
        this.defaultEditors.put(pathClass, new PathEditor());
    }
    this.defaultEditors.put(Pattern.class, new PatternEditor());
    // other code......
}

1.3、Converter

package org.springframework.core.convert.converter;

public interface Converter<S, T> {
    T convert(S source);
}

此外,spring 还提供了 GenericConverter、ConditionalConverter,利用 TypeDescriptor 对转换的类型进行了封装,功能更加强大

public interface GenericConverter {
    Set<ConvertiblePair> getConvertibleTypes(); // 支持转换的类型对
    Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);    // 调用该接口进行对象转换
}

public interface ConditionalConverter {
    boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType);
}

1.4、Formatter 接口

Formatter 接口用于实现 Object <-> String 的相互转换。接口如下图所示,其中 Printer 用于将 Object 转成 String,而 Parser 用于将 String 转成 Object。这和 jdk 提供的 PropertyEditor 有些类似,但是比 jdk 更加方便,更加轻量级

package org.springframework.format;

public interface Formatter<T> extends Printer<T>, Parser<T> {

}

1.5、ConversionService

ConversionService 是一个用于类型转换的接口,代码如下所示:

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);
}

默认实现是 spring-context 包的 org.springframework.format.support.FormattingConversionService,使用了策略模式,将具体的类型转换请求,交给对应的 GenericConverter 进行类型转换。FormattingConversionService 支持添加自定义的 Converter 和 Formatter,如果 Converter 不是 GenericConverter 接口的实现类,则会使用 ConverterAdapter 适配器将 Converter 转换成 GenericConverter 实现类;添加 Formatter 也是如此。

public class FormattingConversionService extends GenericConversionService
        implements FormatterRegistry, EmbeddedValueResolverAware {
    public void addFormatter(Formatter<?> formatter) {
        Class<?> fieldType = GenericTypeResolver.resolveTypeArgument(formatter.getClass(), Formatter.class);
        if (fieldType == null) {
            throw new IllegalArgumentException("Unable to extract parameterized field type argument from Formatter [" +
                    formatter.getClass().getName() + "]; does the formatter parameterize the <T> generic type?");
        }
        addFormatterForFieldType(fieldType, formatter);
    }

    // 添加 Object -> String、String -> Object 类型转换器
    public void addFormatterForFieldType(Class<?> fieldType, Formatter<?> formatter) {
        addConverter(new PrinterConverter(fieldType, formatter, this));
        addConverter(new ParserConverter(fieldType, formatter, this));
    }
}

public class GenericConversionService implements ConfigurableConversionService {
    public void addConverter(Converter<?, ?> converter) {
        GenericConverter.ConvertiblePair typeInfo = getRequiredTypeInfo(converter, Converter.class);
        Assert.notNull(typeInfo, "Unable to the determine sourceType <S> and targetType " +
                "<T> which your Converter<S, T> converts between; declare these generic types.");
        addConverter(new ConverterAdapter(typeInfo, converter));
    }
}

2、基于 xml 的类型转换

在进行源码分析之前,我们先来看一下例子,代码如下所示:

<bean class="net.dwade.spring.boot.PropertyEditorTestBean">
    <property name="date" value="2018-02-18 11:00:00" />
</bean>

public class PropertyEditorTestBean {

    private Date date;

    public void setDate(Date date) {
        this.date = date;
    }

    @PostConstruct
    public void init() {
        System.out.println( date );
    }

}

在没有额外设置的情况下,直接抛出异常了,异常堆栈如下所示:

Caused by: java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'java.util.Date' for property 'date': no matching editors or conversion strategy found
    at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:306) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
    at org.springframework.beans.AbstractNestablePropertyAccessor.convertIfNecessary(AbstractNestablePropertyAccessor.java:588) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
    at org.springframework.beans.AbstractNestablePropertyAccessor.convertForProperty(AbstractNestablePropertyAccessor.java:615) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
    at org.springframework.beans.BeanWrapperImpl.convertForProperty(BeanWrapperImpl.java:216) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.convertForProperty(AbstractAutowireCapableBeanFactory.java:1577) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1536) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1276) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553) ~[spring-beans-4.3.13.RELEASE.jar:4.3.13.RELEASE]

怎么解决上面这个问题呢?结合前面的介绍,有很多种方案,个人列举以下解决方案:

  • 为 spring 的 ConfigurableBeanFactory 指定 ConversionService,怎么指定?利用 spring 的 BeanFactoryPostProcessor 接口,默认情况下是 null。废话不多说,上代码:
public class MyBeanFactoryProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        FormattingConversionService service = new FormattingConversionService();
        service.addConverter( new StringToDateConverter() );
        beanFactory.setConversionService( service );
    }
}

public class StringToDateConverter implements Converter<String, Date> {

    private String[] patterns = {"yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss.SSS"};

    @Override
    public Date convert(String source) {
        if ( StringUtils.isEmpty( source ) ) {
            return null;
        }
        for ( String pattern : patterns ) {
            try {
                return new SimpleDateFormat( pattern ).parse( source );
            } catch (Exception e) {
                // ignore exception, do next pattern parse.
            }
        }
        return null;
    }
}

简单的解释下,MyBeanFactoryProcessor 实现了 BeanFactoryPostProcessor 接口,可以为 ConfigurableBeanFactory 设置 ConversionService,用于添加类型转换器 StringToDateConverter,实现 String -> java.util.Date 类型转换。关于 BeanFactoryPostProcessor,不清楚的童鞋请百度 / google。

  • 利用 org.springframework.beans.factory.config.CustomEditorConfigurer 添加 java.beans.PropertyEditor,这种方法稍微麻烦点,主要的思路就是往 ConfigurableBeanFactory 添加自定义的 PropertyEditor,下面给出注解的配置,当然也可以利用 xml 往 spring 容器中配置 CustomEditorConfigurer
@Bean
public CustomEditorConfigurer customEditorConfigurer() {
    CustomEditorConfigurer editorConfig = new CustomEditorConfigurer();
    PropertyEditorRegistrar registrar = new PropertyEditorRegistrar(){
        @Override
        public void registerCustomEditors(PropertyEditorRegistry registry) {
            registry.registerCustomEditor( Date.class, new CustomDateEditor(new SimpleDateFormat( "yyyy-MM-dd" ), true) );
        }};
    editorConfig.setPropertyEditorRegistrars( new PropertyEditorRegistrar[]{registrar} );
    return editorConfig;
}

2.1、BeanWrapper

spring 在创建 Bean 的时候,首先会使用 BeanWrapper 接口进行属性注入,默认使用 BeanWrapperImpl,BeanWrapper 接口继承至 TypeConverter,说明 BeanWrapper 提供了类型转换的功能,类图如下所示:

image

为了方便理解后续的类型转换原理,我们有必要了解下 BeanWrapper 对象的创建过程:
1. 利用实例化的 bean 对象构建 BeanWrapperImpl
2. 为 BeanWrapper 设置 ConversionService,默认情况下 ConfigurableBeanFactory 不会创建 ConversionService,因此 BeanWrapperImpl 中该对象为 null
3. 添加 PropertyEditor,可以通过 ConfigurableBeanFactory#addPropertyEditorRegistrar(PropertyEditorRegistrar registrar)ConfigurableBeanFactory#registerCustomEditor(Class

AbstractAutowireCapableBeanFactory.java
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
    // 利用 InstantiationStrategy 实例化对象
    Object beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
    BeanWrapper bw = new BeanWrapperImpl(beanInstance); // 创建 BeanWrapperImpl
    initBeanWrapper(bw);    // 使用 ConversionService 初始化 BeanWrapper
    return bw;
}

AbstractBeanFactory.java
protected void initBeanWrapper(BeanWrapper bw) {
    bw.setConversionService(getConversionService());    // 获取 ConfigurableBeanFactory 的 ConversionService
    registerCustomEditors(bw);  // 根据 ConfigurableBeanFactory 设置的 PropertyEditorRegistrar、customEditors 注册 PropertyEditor
}

2.2、类型转换

首先,我们来看下调用栈:

image

spring 在实例化 bean 之后,会进行属性注入,这个时候需要调用 BeanWrapper 提供的类型转换接口,实际上是调用父类 AbstractNestablePropertyAccessor#convertIfNecessary() 方法,代码如下:

protected Object convertForProperty(String propertyName, Object oldValue, Object newValue, TypeDescriptor td) 
    throws TypeMismatchException {
    return convertIfNecessary(propertyName, oldValue, newValue, td.getType(), td);
}

private Object convertIfNecessary(String propertyName, Object oldValue, Object newValue, Class<?> requiredType,
            TypeDescriptor td) throws TypeMismatchException {
    return this.typeConverterDelegate.convertIfNecessary(propertyName, oldValue, newValue, requiredType, td);    
}

具体的转换逻辑是交给 TypeConverterDelegate 进行处理的(估且把它理解成工具类),看到这里,比较好奇的是这个 TypeConverterDelegate 对象是如何创建的,我们先看一下 BeanWrapperImpl 的继承关系图:

image

原来在父类 AbstractNestablePropertyAccessor 的构造方法中创建的,并且传入了 BeanWrapperImpl 对象

protected AbstractNestablePropertyAccessor() {
    this(true);
}

protected AbstractNestablePropertyAccessor(boolean registerDefaultEditors) {
    if (registerDefaultEditors) {
        registerDefaultEditors();
    }
    this.typeConverterDelegate = new TypeConverterDelegate(this);
}

public TypeConverterDelegate(PropertyEditorRegistrySupport propertyEditorRegistry) {
    this(propertyEditorRegistry, null);
}

public TypeConverterDelegate(PropertyEditorRegistrySupport propertyEditorRegistry, Object targetObject) {
    this.propertyEditorRegistry = propertyEditorRegistry;
    this.targetObject = targetObject;
}

OK,看到这里就清楚了,转换逻辑是由 TypeConverterDelegate#convertIfNecessary 方法完成的,代码比较长,老夫就不贴代码了,请结合下面的流程图加以理解。首先会查找自定义的 PropertyEditor,如果有则直接进行类型转换,将 String 转成对应的类型;如果没有支持的 PropertyEditor,并且 ConversionService 不为 null,则尝试使用 ConversionService 进行类型转换。此时,如果仍然没有转换成功,则尝试查找内置的 PropertyEditor,并且由 PropertyEditorRegistrySupport#createDefaultEditors() 注册内置的 PropertyEditor 以支持类型转换,这个方法里面涵括了 spring 默认支持的类型转换,包括 String -> File,String -> Resource,String -> Class 等等,具体请参考官方文档

下图描述了 spring 创建 bean,以及利用 BeanWrapper 进行 IOC 注入的主要逻辑(查看原图):

image

如上图所示,在 spring 实例化 bean 之后,便会根据 BeanDefinition 定义的 PropertyValues 进行属性注入。一般而言,除了 spring 或者框架内置的 BeanDefinitionPropertyValues 大多是空的,如果是从 xml 获取的 BeanDefinition 一般是存在 PropertyValues的,而注解注入是不存在的(注入的原理不一样)。在进行类型转换之前,需要对定义的值进行解析,比如 SpEL 表达式;然后把属性值交给 BeanWrapper 进行转换,把转换之后的值通过 setter 方法给 bean 赋值,从而完成注入功能。

有一点需要补充的是,TypeConverterDelegate 在查找内置的 PropertyEditor 时,如果不存在对应的 PropertyEditor,则会根据 SPI 查找 PropertyEditor。比如,”mypackage.MyDomainClass” -> “mypackage.MyDomainClassEditor” 类型转换,则会尝试根据 “类名 + Editor” 加载 PropertyEditor 对应的 class,代码如下所示:

TypeConverterDelegate.java

private PropertyEditor findDefaultEditor(Class<?> requiredType) {
    PropertyEditor editor = null;
    if (requiredType != null) {
        // 查找内置的 PropertyEditor
        editor = this.propertyEditorRegistry.getDefaultEditor(requiredType);
        if (editor == null && String.class != requiredType) {
            // 尝试获取 requiredType 的全类名 + Editor(SPI)
            editor = BeanUtils.findEditorByConvention(requiredType);
        }
    }
    return editor;
}

2.3、TypeConverterDelegate

由上面可知,TypeConverterDelegate 在类型转换过程中起到很关键的作用,我们有必要聊一聊这个 TypeConverterDelegate。它没有实现任何接口,并且内部持有 PropertyEditorRegistrySupport 的引用(实际上是 BeanWrapperImpl 对象),代码如下所示:

class TypeConverterDelegate {

    private final PropertyEditorRegistrySupport propertyEditorRegistry;

    private final Object targetObject;

    public <T> T convertIfNecessary(Object newValue, Class<T> requiredType, MethodParameter methodParam) throws IllegalArgumentException { //...... }
    public <T> T convertIfNecessary(Object newValue, Class<T> requiredType, Field field) throws IllegalArgumentException { //...... }
    public <T> T convertIfNecessary(String propertyName, Object oldValue, Object newValue, Class<T> requiredType) throws IllegalArgumentException { //...... }
    public <T> T convertIfNecessary(String propertyName, Object oldValue, Object newValue, Class<T> requiredType, TypeDescriptor typeDescriptor) throws IllegalArgumentException {
        //......
    }

    private PropertyEditor findDefaultEditor(Class<?> requiredType) {  //...... }
    private Object doConvertValue(Object oldValue, Object newValue, Class<?> requiredType, PropertyEditor editor) { //...... }

}

实际上,它代理了 BeanWrapper 的某些方法,比如查找 PropertyEditor,并且对 BeanWrapper 的转换逻辑进行了增强,应该是 代理 + 装饰 模式的结合体。TypeConverterDelegate 的类型转换逻辑,比 BeanWrapperImpl 更加复杂,增加了很多功能,比如支持 Collection、Map、数组 等类型的转换,还增加了 ConversionService 的支持

3、基于注解的类型转换

前面我们分析了基于 xml 的类型转换,主要依赖 BeanWrapper,但是基于注解的IOC注入,是基于 BeanPostProcessor 完成的,现在我们来看看 spring 是如何完成类型转换的。还是刚才的例子,只不过我们换成了注解,利用注解的方式为 Test 注入 java.util.Date 对象。

Test.java
@Component
public class Test {

    @Value("2017-02-20 14:00:00")
    private Date date;

    @PostConstruct
    public void init() {
        System.out.println( date );
    }

}

3.1、spring 注解注入原理

我们先来了解下 spring 注解注入的基本原理,核心思想是基于 InstantiationAwareBeanPostProcessor 后置处理器( BeanPostProcessor 的子类),在 bean 实例化之后、bean 初始化之前,获取 bean 对象的 @Resource@Autowired@Qualifier@Value 等注解,并且获取需要注入的值(包括依赖的对象,或者数据),使用反射的手段为 bean 设置属性值。大致原理就是这样,但是实现上面很复杂,比如要考虑如何支持 SpEL,支持动态代理、类型转换,等等。由于篇幅有限,这里只简述下基本原理。

下面列出了相关的源码,感兴趣的童鞋可以进入深入分析:
- AutowiredAnnotationBeanPostProcessor:位于 spring-beans 模块,用于处理 @Autowired、@Value 注解注入
- CommonAnnotationBeanPostProcessor:位于 spring-context 模块,用于处理 @Resource、@EJB 注解注入

首先,我们来看一下方法调用栈,如下图所示:

image

AutowiredAnnotationBeanPostProcessor 实现了 InstantiationAwareBeanPostProcessor 接口,重写了 postProcessPropertyValues 方法,读取 @Autowired、@Value 注解,把这些注解封装成 InjectionMetadata 对象,然后调用其 inject 方法进行属性注入,而 InjectionMetadata 会遍历内部的 InjectedElement 对象(包括 Field、Method 实现的),并对其进行注入,由于我们这个 @Value 注解是标注在字段上面的,因此是 AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement 实现。注入的过程分为两步,首先,根据已有的条件获取依赖的对象,这一步是由 DefaultListableBeanFactory 完成,转换的逻辑就是在这一步完成的;然后,反射调用字段,或者方法,为 bean 赋值,从而完成注入的逻辑。关键代码如下所示:

AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement.java

@Override
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
    Field field = (Field) this.member;
    Object value;
    if (this.cached) {  // 直接从缓存中取出数据
        value = resolvedCachedArgument(beanName, this.cachedFieldValue);
    }
    else {
        DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
        desc.setContainingClass(bean.getClass());
        Set<String> autowiredBeanNames = new LinkedHashSet<String>(1);
        TypeConverter typeConverter = beanFactory.getTypeConverter();
        try {
            value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
        }
        catch (BeansException ex) {
            throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
        }
        synchronized (this) {
            // 将依赖注入的 bean 放入 BeanFactory 的缓存中,并设置为已缓存,方便后续取用
        }
    }
    if (value != null) {    // 反射为属性赋值
        ReflectionUtils.makeAccessible(field);
        field.set(bean, value);
    }
}

由上面的分析可知,对注入的 value 进行解析的逻辑是交给 BeanFactory 完成的,下面我们分析下具体的实现

3.2、类型转换

BeanFactory 会解析其依赖注入的值,首先需要处理原始值,因为可能会包括 SpEL 表达式;然后获取 TypeConverter 对象,并进行类型转换,返回对应类型的值。看到这里便很清晰了,对注解的类型转换仍然是交给 TypeConverter,但是与 xml 的注入不一样的是,xml 拿到的 TypeConverter 就是 BeanWrapper 自身,而注解默认是 SimpleTypeConverter。不管是 SimpleTypeConverter,还是 BeanWrapperImpl,具体的转换逻辑都是交给 TypeConverterDelegate 处理的,请参考前面的内容

DefaultListableBeanFactory.java

public Object doResolveDependency(DependencyDescriptor descriptor, String beanName,
            Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {

    InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
    try {
        Class<?> type = descriptor.getDependencyType();

        // 处理 SpEL 表达式
        Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
        if (value != null) {
            if (value instanceof String) {
                String strVal = resolveEmbeddedValue((String) value);
                BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
                value = evaluateBeanDefinitionString(strVal, bd);
            }

            // 获取 TypeConverter,并对 value 值进行类型转换
            TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
            return (descriptor.getField() != null ?
                    converter.convertIfNecessary(value, type, descriptor.getField()) :
                    converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
        }
        // 省略若干代码
    }
    finally {
        ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
    }
}

我们注意到 DefaultListableBeanFactory 对象的 typeConverter 默认是 null,因此默认返回 SimpleTypeConverter,我们看下这个 getTypeConverter 方法便一目了然,如果我们希望添加自己的类型转换器,可以为 ConfigurableBeanFactory 指定 TypeConverter,从而达到相同的目的。

@Override
public TypeConverter getTypeConverter() {
    TypeConverter customConverter = getCustomTypeConverter();
    if (customConverter != null) {
        return customConverter;
    }
    else {  // 创建 SimpleTypeConverter 对象,并且指定 ConverionService 和 PropertyEditor
        SimpleTypeConverter typeConverter = new SimpleTypeConverter();
        typeConverter.setConversionService(getConversionService());
        registerCustomEditors(typeConverter);
        return typeConverter;
    }
}

protected TypeConverter getCustomTypeConverter() {
    return this.typeConverter;
}

猜你喜欢

转载自blog.csdn.net/dwade_mia/article/details/79340302