ConversionService是类型转换服务的接口,最涉及的类有以下:
学习类型转换服务之前我们先看看各个接口是做什么的
ConversionService
接口的方法很简单,就是判断是否可以两种类型是否可以转换,和转换方法
从名字就可以看出ConverterRegistry
是要实现转换器注册表的接口,添加和移除Converter
和GenericConverter
。
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
继承了ConversionService
和ConversionRegistry
接口,从类型转换服务涉及的类可以看出ConversionService
类型转换服务都是需要和ConverterRegistry
转换器注册表接口配合使用的。所以ConversionService
的实现类都是实现了ConfigurableConversionService
接口的。
Converter
是一个通用的类型转换器,它可以将一个类型转换为另一个类型。它只能转换一种类型,因此需要为每种类型都定义一个Converter
。
GenericConverter
是一个更通用的类型转换器,它可以将多种类型转换为多种类型。它可以处理多种不同的类型转换场景,因此可以减少定义Converter
的数量。GenericConverter
可以在转换过程中使用类型信息来决定如何转换。
总的来说,Converter
适用于单一类型转换,而GenericConverter
适用于多种类型转换。
GenericConversionService
也提供了一个内部类ConverterAdapter
,用来将Converter
适配成GenericConverter
,这里用了适配器模式,详细内容可以点击看适配器模式
首先看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
。
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