【Spring】关于Spring 的类型转换 ConversionService TypeConverter 等
本文已参与「新人创作礼」活动,一起开启掘金创作之路。
前言
Spring 框架层面的转换能力,主要一部分都是由 ConversionService 提供,本章节简单聊一下 Spring 转换服务相关:
- 转换器
API:ConverterConverterFactoryGenericConverter等 - 转换服务:
ConversionService系列 Formatter与Converter的整合- 统一转换服务出口
TypeConverter
转换器 API
Converter
@FunctionalInterface
public interface Converter<S, T> {
@Nullable
T convert(S source);
}
- 很简单的一个函数式接口,
S转换为T - 示例略
ConverterFactory
public interface ConverterFactory<S, R> {
<T extends R> Converter<S, T> getConverter(Class<T> targetType);
}
- 允许
S转换为R子类集合,即一对多的转换 - 可参考官方提供的实现如
NumberToNumberConverterFactory
ConditionalConverter
public interface ConditionalConverter {
boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType);
}
matches基于类型判断是否匹配- 后文提到的
GenericConverter会大量使用该接口
GenericConverter
public interface GenericConverter {
@Nullable
Set<ConvertiblePair> getConvertibleTypes();
@Nullable
Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
final class ConvertiblePair {
private final Class<?> sourceType;
private final Class<?> targetType;
// ...
}
}
- 这是最灵活最复杂的一个转换器接口,因为它支持
多对多的转换服务 - 具体的转换类型由内部类
ConvertiblePair维护,方法getConvertibleTypes返回该转换器支持的转换类型集合
转换服务
ConversionService
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);
}
canConvert,是否支持目标类型的转换convert由转换服务(选择对应的转换器)进行转换
ConverterRegistry
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);
}
XXXRegistry,注册(管理)中心的模式- 提供对
转换器的注册与管理
ConfigurableConversionService
public interface ConfigurableConversionService extends ConversionService, ConverterRegistry {
}
- 它的子类是一个
ConversionService,负责选择转换器进行对应类型的转换 - 它的子类是一个
ConverterRegistry,负责维护一组转换器
GenericConversionService
-
转换服务的所有逻辑基本在这个类实现:转换器的维护、指定类型的转换等
-
它的实现是否精巧,借助两个内部类:
Converts维护ConvertiblePair到ConvertersForPair关系,即根据转换数据的类型获取转换器集合ConvertersForPair维护对应的转换器集合,即获取唯一一个转换器实例进行转换操作,这里获取的就是符合条件(比如match方法)的第一个转换器
-
细节过多就不展开了,感兴趣可以自己看下
DefaultConversionService
ConversionService的默认实现- 没什么额外的逻辑,主要是默认注册了很多
转换器,基本可以应对所有普通的转换类型
格式化与类型转换的整合
Printer
@FunctionalInterface
public interface Printer<T> {
String print(T object, Locale locale);
}
Parser
@FunctionalInterface
public interface Parser<T> {
T parse(String text, Locale locale) throws ParseException;
}
Formatter
public interface Formatter<T> extends Printer<T>, Parser<T> {
}
- 格式化,其实就可以看作一种类型转换:
String和T之间的转换 - 所有可以理解为一个
Formatter对应两个转换器
FormatterRegistry
public interface FormatterRegistry extends ConverterRegistry {
void addPrinter(Printer<?> printer);
void addParser(Parser<?> parser);
void addFormatter(Formatter<?> formatter);
void addFormatterForFieldType(Class<?> fieldType, Formatter<?> formatter);
void addFormatterForFieldType(Class<?> fieldType, Printer<?> printer, Parser<?> parser);
void addFormatterForFieldAnnotation(AnnotationFormatterFactory<? extends Annotation> annotationFormatterFactory);
}
Formatter的注册中心,它同时还是一个ConverterRegistry,这里其实是一个组合的关系- 支持
Printer和Parser的单独注册以及Formatter的注册
FormattingConversionService
public class FormattingConversionService extends GenericConversionService
implements FormatterRegistry, EmbeddedValueResolverAware {
// ...
// 对于 Printer 适配成 PrinterConverter 注册
@Override
public void addPrinter(Printer<?> printer) {
Class<?> fieldType = getFieldType(printer, Printer.class);
addConverter(new PrinterConverter(fieldType, printer, this));
}
// 对于 Parser 适配成 ParserConverter 注册
@Override
public void addParser(Parser<?> parser) {
Class<?> fieldType = getFieldType(parser, Parser.class);
addConverter(new ParserConverter(fieldType, parser, this));
}
// 一个 Formatter 对于两个 Converter
@Override
public void addFormatterForFieldType(Class<?> fieldType, Formatter<?> formatter) {
addConverter(new PrinterConverter(fieldType, formatter, this));
addConverter(new ParserConverter(fieldType, formatter, this));
}
// ...
}
- 之前提到,
Formatter可以理解为T到String类型的Converter,FormattingConversionService就依赖这个思想实现 - 对于
Printer和Parser分别适配成PrinterConverter和ParserConverter注册,适配器设计模式的经典场景 - 注册方法
addConverter由父类GenericConversionService提供,组合设计模式的经典场景
DefaultFormattingConversionService
- 跟
DefaultConversionService的思路一样,同时也是DefaultConversionService的子类 - 在
DefaultConversionService注册的转换器之上,再注册一些默认的Formatter
TypeConverter
public interface TypeConverter {
@Nullable
<T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType) throws TypeMismatchException;
@Nullable
<T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType,
@Nullable MethodParameter methodParam) throws TypeMismatchException;
@Nullable
<T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType, @Nullable Field field)
throws TypeMismatchException;
@Nullable
default <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType,
@Nullable TypeDescriptor typeDescriptor) throws TypeMismatchException {
throw new UnsupportedOperationException("TypeDescriptor resolution not supported");
}
}
- 除了
转换服务,JDK提供的PropertyEditor也提供类似的机制,TypeConverter统一上述所有转换的出口 - 子类
TypeConverterSupport作为抽象基类,把上述方法的实现都委托给TypeConverterDelegate TypeConverterDelegate再往下就是基于PropertyEditor和ConversionService进行转换了,细节不再深入Spring容器中的默认TypeConverter实例为SimpleTypeConverter
总结
Spring 的数据转换在体现在方方面面:
- 单纯的类型转换,比如
BeanFactory#getBean方法的类型转换等 - 数据绑定,比如
DataBinder绑定数据时,必然也涉及类型的转换 - 等等