Spring中的ConversionService源碼解析
ConversionService是什么
ConversionService是類型轉(zhuǎn)換服務(wù)的接口,最涉及的類有以下:
學(xué)習(xí)類型轉(zhuǎn)換服務(wù)之前我們先看看各個(gè)接口是做什么的
ConversionService接口
ConversionService接口的方法很簡單,就是判斷是否可以兩種類型是否可以轉(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)化為特定類型的對(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類型的接口,Parse接口就是將String類型轉(zhuǎn)換為特定類型對(duì)象的接口。在Spring中Formatter接口的實(shí)現(xiàn)也是非常多
所以如果不需要使用String類型和對(duì)象類型的轉(zhuǎn)換,使用GenericConversionService或DefaultConversionService就可以了
ConfigurableConversionService接口
ConfigurableConversionService繼承了ConversionService和ConversionRegistry接口,從類型轉(zhuǎn)換服務(wù)涉及的類可以看出ConversionService類型轉(zhuǎn)換服務(wù)都是需要和ConverterRegistry轉(zhuǎn)換器注冊(cè)表接口配合使用的。所以ConversionService的實(shí)現(xiàn)類都是實(shí)現(xiàn)了ConfigurableConversionService接口的。
Converter和GenericConverter的區(qū)別
Converter是一個(gè)通用的類型轉(zhuǎn)換器,它可以將一個(gè)類型轉(zhuǎn)換為另一個(gè)類型。它只能轉(zhuǎn)換一種類型,因此需要為每種類型都定義一個(gè)Converter。
GenericConverter是一個(gè)更通用的類型轉(zhuǎn)換器,它可以將多種類型轉(zhuǎn)換為多種類型。它可以處理多種不同的類型轉(zhuǎn)換場景,因此可以減少定義Converter的數(shù)量。GenericConverter可以在轉(zhuǎn)換過程中使用類型信息來決定如何轉(zhuǎn)換。
總的來說,Converter適用于單一類型轉(zhuǎn)換,而GenericConverter適用于多種類型轉(zhuǎn)換。 GenericConversionService也提供了一個(gè)內(nèi)部類ConverterAdapter,用來將Converter適配成GenericConverter,這里用了適配器模式
ConversionService的各個(gè)實(shí)現(xiàn)類有什么區(qū)別?又該如何選擇呢?
首先看DefaultFormattingConversionService的構(gòu)造方法,里面通過DefaultConversionService的靜態(tài)方法添加了默認(rèn)的一些Converter還有一些默認(rèn)的Formatter,可以猜測到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); }
測試結(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類型轉(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)出幾種常見方法
相關(guān)文章
Java Validation Api實(shí)現(xiàn)原理解析
這篇文章主要介紹了Java Validation Api實(shí)現(xiàn)原理解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09java中Spring Security的實(shí)例詳解
這篇文章主要介紹了java中Spring Security的實(shí)例詳解的相關(guān)資料,spring security是一個(gè)多方面的安全認(rèn)證框架,提供了基于JavaEE規(guī)范的完整的安全認(rèn)證解決方案,需要的朋友可以參考下2017-09-09詳解springMVC之與json數(shù)據(jù)交互方法
本篇文章主要介紹了詳解springMVC之與json數(shù)據(jù)交互方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-05-05在Java8與Java7中HashMap源碼實(shí)現(xiàn)的對(duì)比
這篇文章主要介紹了在Java8與Java7中HashMap源碼實(shí)現(xiàn)的對(duì)比,內(nèi)容包括HashMap 的原理簡單介紹、結(jié)合源碼在Java7中是如何解決hash沖突的以及優(yōu)缺點(diǎn),結(jié)合源碼以及在Java8中如何解決hash沖突,balance tree相關(guān)源碼介紹,需要的朋友可以參考借鑒。2017-01-01Java數(shù)字轉(zhuǎn)換工具類NumberUtil的使用
NumberUtil是一個(gè)功能強(qiáng)大的Java工具類,用于處理數(shù)字的各種操作,包括數(shù)值運(yùn)算、格式化、隨機(jī)數(shù)生成和數(shù)值判斷,下面就來介紹一下NumberUtil的具體使用,感興趣的可以了解一下2025-02-02springboot無法跳轉(zhuǎn)頁面的問題解決方案
這篇文章主要介紹了springboot無法跳轉(zhuǎn)頁面的問題解決方案,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09一篇文章教你如何用多種迭代寫法實(shí)現(xiàn)二叉樹遍歷
這篇文章主要介紹了C語言實(shí)現(xiàn)二叉樹遍歷的迭代算法,包括二叉樹的中序遍歷、先序遍歷及后序遍歷等,是非常經(jīng)典的算法,需要的朋友可以參考下2021-08-08