作用
提供类型转换服务,可以将A类型数据转换为B类型数据。
主要实现与调用
主要实现为ApplicationConversionService
在启动springboot项目时。通过ApplicationConversionService.getSharedInstance()。向BeanFactory与Environment中设置相关对象,提供类型转换服务。
我们具体可以在TypeConverter中看到具体调用过程。
继承关系
ConversionService
类型转换服务接口。定义一下方法:
- canConvert 判断两个类型间是否可以转换
- convert 类型类型
ConverterRegistry
转换器注册接口。定义了转换器的添加删除和查询功能。
下面的类都是基于上面两个类的子类。
FormatterRegistry
添加对Formatter的注册,Formatter为格式化转换器。比如子类:YearFormatter,可以将字符串类型转换为Year类型。
//TODO 如果有必要在详细研究。
GenericConversionService
通用的转换服务
在说明这个类的方法前我们需要先说明和它相关的几个类的作用。这样我们才方便继续理解当前代码:
Converter<?,?> GenericConverter ConvertiblePair Converters
Converter
转换类。这个类有两个范型,代表着将数据从A类类型转换为B类型。这个接口只支持一组类型的转换。
GenericConverter
通用的转换类。这个类没有范型。支持多组类型的转换。
ConvertiblePair
GenericConverter的子类。分装了转换时 原类型与目标类型。
Converters
保存多个GenericConverter。并通过转换类型查找适合当前转换的GenericConverter。
** 下面我们继续说明GenericConversionService**
addConverter
@Override
public void addConverter(GenericConverter converter) {
this.converters.add(converter);
invalidateCache();
}
我们可以看到其实就是将converter添加到conveters内
canConvert
@Override
public boolean canConvert(@Nullable Class<?> sourceType, Class<?> targetType) {
Assert.notNull(targetType, "Target type to convert to cannot be null");
return canConvert((sourceType != null ? TypeDescriptor.valueOf(sourceType) : null),
TypeDescriptor.valueOf(targetType));
}
@Override
public boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
Assert.notNull(targetType, "Target type to convert to cannot be null");
if (sourceType == null) {
return true;
}
GenericConverter converter = getConverter(sourceType, targetType);
return (converter != null);
}
@Nullable
protected GenericConverter getConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {
ConverterCacheKey key = new ConverterCacheKey(sourceType, targetType);
GenericConverter converter = this.converterCache.get(key);
if (converter != null) {
return (converter != NO_MATCH ? converter : null);
}
converter = this.converters.find(sourceType, targetType);
if (converter == null) {
converter = getDefaultConverter(sourceType, targetType);
}
if (converter != null) {
this.converterCache.put(key, converter);
return converter;
}
this.converterCache.put(key, NO_MATCH);
return null;
}
canConvert 也就时判断conveters内是否有符合当前类型的conveter
convert
@Override
@Nullable
public Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
Assert.notNull(targetType, "Target type to convert to cannot be null");
if (sourceType == null) {
Assert.isTrue(source == null, "Source must be [null] if source type == [null]");
return handleResult(null, targetType, convertNullSource(null, targetType));
}
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() + "]");
}
GenericConverter converter = getConverter(sourceType, targetType);
if (converter != null) {
Object result = ConversionUtils.invokeConverter(converter, source, sourceType, targetType);
return handleResult(sourceType, targetType, result);
}
return convert(source, sourceType, targetType);
}
我们看到类型转换就是获取到合适的转换器,并进行执行,同时handleResult 进行类型判断。
ApplicationConversionService
这个类是在父类基础上添加了一些默认的转换器,具体如下:
public static void addApplicationConverters(ConverterRegistry registry) {
addDelimitedStringConverters(registry);
registry.addConverter(new StringToDurationConverter());
registry.addConverter(new DurationToStringConverter());
registry.addConverter(new NumberToDurationConverter());
registry.addConverter(new DurationToNumberConverter());
registry.addConverter(new StringToPeriodConverter());
registry.addConverter(new PeriodToStringConverter());
registry.addConverter(new NumberToPeriodConverter());
registry.addConverter(new StringToDataSizeConverter());
registry.addConverter(new NumberToDataSizeConverter());
registry.addConverter(new StringToFileConverter());
registry.addConverter(new InputStreamSourceToByteArrayConverter());
registry.addConverterFactory(new LenientStringToEnumConverterFactory());
registry.addConverterFactory(new LenientBooleanToEnumConverterFactory());
}
在mvc项目中,会加载 beanFactory的转换器。具体在mvc中说明
public static void addBeans(FormatterRegistry registry, ListableBeanFactory beanFactory) {
Set<Object> beans = new LinkedHashSet<>();
beans.addAll(beanFactory.getBeansOfType(GenericConverter.class).values());
beans.addAll(beanFactory.getBeansOfType(Converter.class).values());
beans.addAll(beanFactory.getBeansOfType(Printer.class).values());
beans.addAll(beanFactory.getBeansOfType(Parser.class).values());
for (Object bean : beans) {
if (bean instanceof GenericConverter) {
registry.addConverter((GenericConverter) bean);
}
else if (bean instanceof Converter) {
registry.addConverter((Converter<?, ?>) bean);
}
else if (bean instanceof Formatter) {
registry.addFormatter((Formatter<?>) bean);
}
else if (bean instanceof Printer) {
registry.addPrinter((Printer<?>) bean);
}
else if (bean instanceof Parser) {
registry.addParser((Parser<?>) bean);
}
}
}