应用的场景描述:
在基于xml的配置中,我们往往通过字面值为Bean各种类型的属性提供设置值:不管是double类型还是int类型,在配置文件中都对应字符串类型的字面值。
BeanWrapper填充Bean属性时如何将这个字面值转换为对应的double或int等内部类型呢?我们可以隐约地感觉到一定有一个转换器在其中起作用,这个转换器就是属性编辑器。
Spring MVC框架使用多种PropertyEditors分析HTTP请求的各种参数
有的小伙伴可能会问:既然有了PropertyEditor,那为何还需要有Converter呢?其实是因为Java原生的PropertyEditor存在以下两点不足:
- 只能用于字符串和Java对象的转换,不适用于任意两个Java类型之间的转换;
- 对源对象及目标对象所在的上下文信息(如注解、所在宿主类的结构等)不敏感,在类型转换时不能利用这些上下文信息实施高级转换逻辑。
鉴于此,Spring 3.0在核心模型中添加了一个通用的类型转换模块,类型转换模块位于org.springframework.core.convert包中。Spring希望用这个类型转换体系替换Java标准的PropertyEditor。但由于历史原因,Spring将同时支持两者。在Bean配置、Spring MVC处理方法入参绑定中使用它们。
Spring提供了PropertyEditorRegistry来注册自定义的Editor~ 提供了PropertyEditorRegistrar这个注册官来registerCustomEditors。它的实现类只有ResourceEditorRegistrar使用ResourceLoader来加载资源~默认注册了:Resource、InputStream、InputSource、File、Reader等等和资源先关的属性编辑器。
public interface PropertyEditorRegistry { void registerCustomEditor(Class<?> requiredType, PropertyEditor propertyEditor); // propertyPath可以是name,可以是person.name这种复合的~~~~ void registerCustomEditor(@Nullable Class<?> requiredType, @Nullable String propertyPath, PropertyEditor propertyEditor); // 查找一个PropertyEditor @Nullable PropertyEditor findCustomEditor(@Nullable Class<?> requiredType, @Nullable String propertyPath); }
Converter or PropertyEditor?
Spring有两种自动类型转换器,一种是Converter,一种是PropertyEditor。
Converter是类型转换成类型,Editor:从string类型转换为其他类型。
从某种程度上,Converter包含Editor。如果出现需要从string转换到其他类型。首选Editor。
org.springframework.beans.TypeConverter
TypeConverter在org.springframework.expression包中还有一个,注意区分。
// @since 2.0 // 定义类型转换方法的接口。通常(但不一定)与PropertyEditorRegistry接口一起实现 // 通常接口TypeConverter的实现是基于非线程安全的PropertyEditors类,因此也不是线程安全的 public interface TypeConverter { // 将参数中的value转换成requiredType类型 // 从String到任何类型的转换通常使用PropertyEditor类的setAsText方法或ConversionService中的Spring Converter @Nullable <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType) throws TypeMismatchException; // 意义同上,增加了作为转换目标的方法参数,主要用于分析泛型类型,可能是null @Nullable <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType, @Nullable MethodParameter methodParam) throws TypeMismatchException; // 意义同上,增加了转换目标的反射field @Nullable <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType, @Nullable Field field) throws TypeMismatchException; // @since 5.1.4 @Nullable default <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType, @Nullable TypeDescriptor typeDescriptor) throws TypeMismatchException { throw new UnsupportedOperationException("TypeDescriptor resolution not supported"); } }
继承树如下:
TypeConverterSupport
TypeConverter的基本实现类,同时也是BeanWrapperImpl类的依赖类。
public abstract class TypeConverterSupport extends PropertyEditorRegistrySupport implements TypeConverter { @Nullable TypeConverterDelegate typeConverterDelegate; ... //它所有的convertIfNecessary工作都是委托给了TypeConverterDelegate }
TypeConverterDelegate
类型转换的委托类,所有类型转换的工作都由该类完成,即将属性转换为其他类型的Spring内部使用方法(内部实现: 先使用PropertyEditor转换器器转换,如果没找到对应的转换器器,会⽤ConversionService来进⾏行行对象转换。)
// @since 2.0 class TypeConverterDelegate { // PropertyEditorRegistrySupport#findCustomEditor和getConversionService // 就是处理这么一个基本逻辑的~~~~ private final PropertyEditorRegistrySupport propertyEditorRegistry; private final Object targetObject; // ...... }
所以从此处就可以看到,PropertyEditor和ConversionService的差别和联系。
SimpleTypeConverter
不在特定目标对象上运行的TypeConverter接口的简单实现。这是使用完整的BeanWrapperImpl实例来实现任意类型转换需求的替代方法,同时使用相同的转换算法(包括委托给PropertyEditor和ConversionService)。
public class SimpleTypeConverter extends TypeConverterSupport { public SimpleTypeConverter() { this.typeConverterDelegate = new TypeConverterDelegate(this); registerDefaultEditors(); } }
SimpleTypeConverter经常会被作为默认实现。
PropertyEditor用于字符串到其它对象的转换,由于其局限性,spring提供了converter接口,由ConversionService来调用对外提供服务,而TypeConverter综合了上述两种转换方式,交由TypeConverterDelegate来进行转换。
TypeConverterDelegater先使用PropertyEditor转换器器转换,如果没找到对应的转换器器,会⽤ConversionService来进⾏行行对象转换
总结
1.Spring使用ConversionService来convert各种类型.默认提供的是DefaultConversionService.同时它实现了ConverterRegistry接口,所以也可以添加你自定义的converter.
2.Spring提供了3种converter接口,分别是Converter,ConverterFactory和GenericConverter.一般用于1:1, 1:N, N:N的source->target类型转化.
3.在DefaultConversionService内部3种converter都会转化成GenericConverter放到静态内部类Converters中.
4.接口GenericConverter的内部类ConvertiblePair是source的class与target的Class的封装。GenericConversionService的静态内部类ConvertersForPair是多个converter对应的LinkedList的封装。。。GenericConversionService的静态内部类Converters中含有1个Map<ConvertiblePair, ConvertersForPair>用来储存所有converter.
1个GenericConverter可以对应N个ConvertiblePair,1个ConvertiblePair对应的ConvertersForPair中也可以有N个GenericConverter.
Convertible:可转换的
Spring为何要使用ConversionService替代PropertyEditor
此处总结三个原因,供给大家参考:
- ConversionService功能更强大,支持的类型转换范围更广。1. 相比PropertyEditor只提供String<->Object的转换,ConversionService能够提供任意Object<->Object的转换。
- ConverterFactory支持一整个class hierarchy的转换(也就是多态),PropertyEditor则不行
- Java Bean这个规范最初是和Java GUI(Swing)一起诞生的,PropertyEditor接口里有大量和GUI相关的方法,显然已经过时了。1. Java Bean和POJO不是一个概念,Java Bean不仅有getter、setter,还有一系列和Java GUI配套的东西。