Spring中的ConversionService源码解析
作者:啊几
ConversionService是什么
ConversionService是类型转换服务的接口,最涉及的类有以下:

学习类型转换服务之前我们先看看各个接口是做什么的
ConversionService接口
ConversionService接口的方法很简单,就是判断是否可以两种类型是否可以转换,和转换方法

ConversionRegistry接口
从名字就可以看出ConverterRegistry是要实现转换器注册表的接口,添加和移除Converter和GenericConverter。

FormatterRegistry接口
FormatterRegistry接口是ConverterRegistry的子接口


在学这个接口之前要先了解Formatter是什么?
Formatter是什么?
Formatter是一种用于格式化和解析对象的接口,它可以将一个对象转化为字符串,或将一个字符串转化为特定类型的对象。在Spring MVC中,Formatter通常用于将HTTP请求中的参数绑定到Java对象上,或将Java对象转化为HTTP响应中的数据。

Formatter接口继承了Printer和Parse两个接口
public interface Printer<T> {
String print(T object, Locale locale);
}
public interface Parser<T> {
T parse(String text, Locale locale) throws ParseException;
}
Printer接口就是对象转换为String类型的接口,Parse接口就是将String类型转换为特定类型对象的接口。在Spring中Formatter接口的实现也是非常多

所以如果不需要使用String类型和对象类型的转换,使用GenericConversionService或DefaultConversionService就可以了
ConfigurableConversionService接口
ConfigurableConversionService继承了ConversionService和ConversionRegistry接口,从类型转换服务涉及的类可以看出ConversionService类型转换服务都是需要和ConverterRegistry转换器注册表接口配合使用的。所以ConversionService的实现类都是实现了ConfigurableConversionService接口的。

Converter和GenericConverter的区别
Converter是一个通用的类型转换器,它可以将一个类型转换为另一个类型。它只能转换一种类型,因此需要为每种类型都定义一个Converter。
GenericConverter是一个更通用的类型转换器,它可以将多种类型转换为多种类型。它可以处理多种不同的类型转换场景,因此可以减少定义Converter的数量。GenericConverter可以在转换过程中使用类型信息来决定如何转换。
总的来说,Converter适用于单一类型转换,而GenericConverter适用于多种类型转换。 GenericConversionService也提供了一个内部类ConverterAdapter,用来将Converter适配成GenericConverter,这里用了适配器模式
ConversionService的各个实现类有什么区别?又该如何选择呢?
首先看DefaultFormattingConversionService的构造方法,里面通过DefaultConversionService的静态方法添加了默认的一些Converter还有一些默认的Formatter,可以猜测到DefaultFormattingConversionService比DefaultConversionService多添加了默认的Formatter
public DefaultFormattingConversionService(
@Nullable StringValueResolver embeddedValueResolver, boolean registerDefaultFormatters) {
if (embeddedValueResolver != null) {
setEmbeddedValueResolver(embeddedValueResolver);
}
DefaultConversionService.addDefaultConverters(this);
if (registerDefaultFormatters) {
addDefaultFormatters(this);
}
}
下面是默认添加的一些Converter
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));
}
下面是默认添加的一些Formatter
public static void addDefaultFormatters(FormatterRegistry formatterRegistry) {
// Default handling of number values
formatterRegistry.addFormatterForFieldAnnotation(new NumberFormatAnnotationFormatterFactory());
// Default handling of monetary values
if (jsr354Present) {
formatterRegistry.addFormatter(new CurrencyUnitFormatter());
formatterRegistry.addFormatter(new MonetaryAmountFormatter());
formatterRegistry.addFormatterForFieldAnnotation(new Jsr354NumberFormatAnnotationFormatterFactory());
}
// Default handling of date-time values
// just handling JSR-310 specific date and time types
new DateTimeFormatterRegistrar().registerFormatters(formatterRegistry);
if (jodaTimePresent) {
// handles Joda-specific types as well as Date, Calendar, Long
new org.springframework.format.datetime.joda.JodaTimeFormatterRegistrar().registerFormatters(formatterRegistry);
}
else {
// regular DateFormat-based Date, Calendar, Long converters
new DateFormatterRegistrar().registerFormatters(formatterRegistry);
}
}
所以如果要使用Spring自带的一些Formatter和Converter可以使用DefaultFormattingConversionService比DefaultConversionService,如果不需要可以使用FormatterConversionService或GenericConversionService。
ConversionService的使用示例
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = (UserService) applicationContext.getBean("userService");
FormattingConversionService conversionService = new DefaultFormattingConversionService();
//String -> ArrayList
System.out.println(conversionService.convert("1,2,3,4", ArrayList.class));
//boolean -> String
System.out.println(conversionService.convert(true,String.class));
//自定义了一个格式化器,OrderService -> String ,String -> OrderService
conversionService.addFormatter(new Formatter<OrderService>() {
private ObjectMapper objectMapper = new ObjectMapper();
@Override
public String print(OrderService object, Locale locale) {
try {
return objectMapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
@Override
public OrderService parse(String text, Locale locale) throws ParseException {
try {
return objectMapper.readValue(text,OrderService.class);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
});
String result = conversionService.convert(userService.getOrderService(),String.class);
System.out.println(result);
OrderService orderService = conversionService.convert(result, OrderService.class);
System.out.println(orderService);
}
测试结果
[1, 2, 3, 4]
true
{"user":{}}
com.zhouyu.service.OrderService@2bbf180e
到此这篇关于Spring中的ConversionService源码解析的文章就介绍到这了,更多相关ConversionService源码解析内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
