Spring中的ConversionService源碼解析
ConversionService是什么
ConversionService是類(lèi)型轉(zhuǎn)換服務(wù)的接口,最涉及的類(lèi)有以下:

學(xué)習(xí)類(lèi)型轉(zhuǎn)換服務(wù)之前我們先看看各個(gè)接口是做什么的
ConversionService接口
ConversionService接口的方法很簡(jiǎn)單,就是判斷是否可以兩種類(lèi)型是否可以轉(zhuǎn)換,和轉(zhuǎn)換方法

ConversionRegistry接口
從名字就可以看出ConverterRegistry是要實(shí)現(xiàn)轉(zhuǎn)換器注冊(cè)表的接口,添加和移除Converter和GenericConverter。

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


在學(xué)這個(gè)接口之前要先了解Formatter是什么?
Formatter是什么?
Formatter是一種用于格式化和解析對(duì)象的接口,它可以將一個(gè)對(duì)象轉(zhuǎn)化為字符串,或?qū)⒁粋€(gè)字符串轉(zhuǎn)化為特定類(lèi)型的對(duì)象。在Spring MVC中,F(xiàn)ormatter通常用于將HTTP請(qǐng)求中的參數(shù)綁定到Java對(duì)象上,或?qū)ava對(duì)象轉(zhuǎn)化為HTTP響應(yīng)中的數(shù)據(jù)。

Formatter接口繼承了Printer和Parse兩個(gè)接口
public interface Printer<T> {
String print(T object, Locale locale);
}
public interface Parser<T> {
T parse(String text, Locale locale) throws ParseException;
}
Printer接口就是對(duì)象轉(zhuǎn)換為String類(lèi)型的接口,Parse接口就是將String類(lèi)型轉(zhuǎn)換為特定類(lèi)型對(duì)象的接口。在Spring中Formatter接口的實(shí)現(xiàn)也是非常多

所以如果不需要使用String類(lèi)型和對(duì)象類(lèi)型的轉(zhuǎn)換,使用GenericConversionService或DefaultConversionService就可以了
ConfigurableConversionService接口
ConfigurableConversionService繼承了ConversionService和ConversionRegistry接口,從類(lèi)型轉(zhuǎn)換服務(wù)涉及的類(lèi)可以看出ConversionService類(lèi)型轉(zhuǎn)換服務(wù)都是需要和ConverterRegistry轉(zhuǎn)換器注冊(cè)表接口配合使用的。所以ConversionService的實(shí)現(xiàn)類(lèi)都是實(shí)現(xiàn)了ConfigurableConversionService接口的。

Converter和GenericConverter的區(qū)別
Converter是一個(gè)通用的類(lèi)型轉(zhuǎn)換器,它可以將一個(gè)類(lèi)型轉(zhuǎn)換為另一個(gè)類(lèi)型。它只能轉(zhuǎn)換一種類(lèi)型,因此需要為每種類(lèi)型都定義一個(gè)Converter。
GenericConverter是一個(gè)更通用的類(lèi)型轉(zhuǎn)換器,它可以將多種類(lèi)型轉(zhuǎn)換為多種類(lèi)型。它可以處理多種不同的類(lèi)型轉(zhuǎn)換場(chǎng)景,因此可以減少定義Converter的數(shù)量。GenericConverter可以在轉(zhuǎn)換過(guò)程中使用類(lèi)型信息來(lái)決定如何轉(zhuǎn)換。
總的來(lái)說(shuō),Converter適用于單一類(lèi)型轉(zhuǎn)換,而GenericConverter適用于多種類(lèi)型轉(zhuǎn)換。 GenericConversionService也提供了一個(gè)內(nèi)部類(lèi)ConverterAdapter,用來(lái)將Converter適配成GenericConverter,這里用了適配器模式
ConversionService的各個(gè)實(shí)現(xiàn)類(lèi)有什么區(qū)別?又該如何選擇呢?
首先看DefaultFormattingConversionService的構(gòu)造方法,里面通過(guò)DefaultConversionService的靜態(tài)方法添加了默認(rèn)的一些Converter還有一些默認(rèn)的Formatter,可以猜測(cè)到DefaultFormattingConversionService比DefaultConversionService多添加了默認(rèn)的Formatter
public DefaultFormattingConversionService(
@Nullable StringValueResolver embeddedValueResolver, boolean registerDefaultFormatters) {
if (embeddedValueResolver != null) {
setEmbeddedValueResolver(embeddedValueResolver);
}
DefaultConversionService.addDefaultConverters(this);
if (registerDefaultFormatters) {
addDefaultFormatters(this);
}
}
下面是默認(rèn)添加的一些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));
}
下面是默認(rèn)添加的一些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));
//自定義了一個(gè)格式化器,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);
}
測(cè)試結(jié)果
[1, 2, 3, 4]
true
{"user":{}}
com.zhouyu.service.OrderService@2bbf180e
到此這篇關(guān)于Spring中的ConversionService源碼解析的文章就介紹到這了,更多相關(guān)ConversionService源碼解析內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot?MongoCustomConversions自定義轉(zhuǎn)換方式
- springboot?ElasticSearch如何配置自定義轉(zhuǎn)換器ElasticsearchCustomConversions
- Spring類(lèi)型轉(zhuǎn)換 ConversionSerivce Convertor解析
- mybatis+springboot發(fā)布postgresql數(shù)據(jù)的實(shí)現(xiàn)
- springboot動(dòng)態(tài)加載jar包動(dòng)態(tài)配置實(shí)例詳解
- springboot實(shí)現(xiàn)excel表格導(dǎo)出幾種常見(jiàn)方法
相關(guān)文章
Java中checkbox實(shí)現(xiàn)跨頁(yè)多選的方法
最近做了一個(gè)項(xiàng)目其中遇到這樣的需求,要實(shí)現(xiàn)checkbox跨頁(yè)多選功能,經(jīng)過(guò)小編整理,順利解決,今天小編給大家分享Java中checkbox實(shí)現(xiàn)跨頁(yè)多選的方法,需要的的朋友參考下2017-01-01
java中throws與try...catch的區(qū)別點(diǎn)
在本篇文章里小編給大家整理了一篇關(guān)于java中throws與try...catch的區(qū)別點(diǎn)的內(nèi)容,需要的朋友們跟著學(xué)習(xí)下。2020-02-02
JDK8中String的intern()方法實(shí)例詳細(xì)解讀
String字符串在我們?nèi)粘i_(kāi)發(fā)中最常用的,當(dāng)然還有他的兩個(gè)兄弟StringBuilder和StringBuilder,接下來(lái)通過(guò)本文給大家介紹JDK8中String的intern()方法詳細(xì)解讀,需要的朋友可以參考下2022-09-09
Mybatis-plus數(shù)據(jù)權(quán)限D(zhuǎn)ataPermissionInterceptor實(shí)現(xiàn)
本文主要介紹了Mybatis-plus數(shù)據(jù)權(quán)限D(zhuǎn)ataPermissionInterceptor實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07
Java HashMap從鏈表到紅黑樹(shù)的"進(jìn)化"過(guò)程詳解
在Java集合框架中,HashMap的底層實(shí)現(xiàn)在JDK 1.8迎來(lái)了一次重大革新:引入了紅黑樹(shù),本文將結(jié)合底層源碼,帶你徹底搞懂HashMap是在什么條件下、如何進(jìn)行樹(shù)化的,感興趣的朋友跟隨小編一起看看吧2026-02-02

