日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Spring的Registrar倒排思想送給你

本文轉(zhuǎn)載自微信公眾號「BAT的烏托邦」,作者YourBatman 。轉(zhuǎn)載本文請聯(lián)系BAT的烏托邦公眾號。

成都做網(wǎng)站、成都網(wǎng)站建設(shè)、成都外貿(mào)網(wǎng)站建設(shè),成都做網(wǎng)站公司-創(chuàng)新互聯(lián)已向成百上千企業(yè)提供了,網(wǎng)站設(shè)計,網(wǎng)站制作,網(wǎng)絡(luò)營銷等服務(wù)!設(shè)計與技術(shù)結(jié)合,多年網(wǎng)站推廣經(jīng)驗,合理的價格為您打造企業(yè)品質(zhì)網(wǎng)站。

請人吃飯不如請人出汗,請人出汗不如送人以漁。A哥春節(jié)繼續(xù)營業(yè),這個時候還能看得下去這種技術(shù)文章的同學(xué)我猜有三類:

  • 要么孤獨了
  • 要么喝醉了
  • 要么喝醉后覺得孤獨了

現(xiàn)實情況往往挺扎心,所以牢記使命,砥礪前行是個好辦法。

上篇文章 把@DateTimeFormat和@NumberFormat注解的實現(xiàn)原理搞清楚了,通過面向元數(shù)據(jù)編程屏蔽了理解層面、實施層面上的差異化。同時,通過手敲代碼案例,扎扎實實、徹徹底底搞明白了@DateTimeFormat等注解有何用以及如何用,從此不再虛。

像AnnotationFormatterFactory、xxxConverter這種均屬于low-level底層API,上手起來一般頗具難度。一個良好的、流行的框架最起碼應(yīng)該是上手簡單的,所以開發(fā)者應(yīng)該是最多關(guān)心到FormattingConversionService/ConversionService層面即止。本文帶你看看Spring是如何做到醬紫的~

本文提綱

版本約定

  • Spring Framework:5.3.x
  • Spring Boot:2.4.x

正文

上文是通過手動調(diào)用API的方式實現(xiàn)元數(shù)據(jù)的解析從而達到數(shù)據(jù)格式化(轉(zhuǎn)換)的目的,而在實際應(yīng)用場景中,作為業(yè)務(wù)開發(fā)者是不可能去直接去操縱API的,畢竟說到底那對開發(fā)者太不友好,使用門檻過高。

因此,本文將介紹的是一種更為“高級”的使用方案,看看Spring是如何做到兼具高擴展性的整合,從而對開發(fā)者十分友好,相信這便也是Spring最有魅力的地方,一起來學(xué)習(xí)學(xué)習(xí)吧。

FormatterRegistry:注冊中心

對于多組件的管理,注冊中心是個很好的解決方案。

FormatterRegistry其實在:9. 細節(jié)見真章,F(xiàn)ormatter注冊中心的設(shè)計很討巧 這篇文章已經(jīng)有過很詳細的分析,學(xué)到了它那非常巧妙的設(shè)計,這里也順道推薦你花幾分鐘前往看看。在這篇文章的末尾,A哥故意留下了一個小尾巴沒講:注冊中心對注解工廠AnnotationFormatterFactory的支持,也就是這個接口方法:

 
 
 
 
  1. FormatterRegistry: 
  2.  
  3.  void addFormatterForFieldAnnotation(AnnotationFormatterFactory annotationFormatterFactory); 

現(xiàn)在時機成熟,本文就來重點關(guān)照它。

該接口方法的唯一實現(xiàn)在FormattingConversionService里:

①:從AnnotationFormatterFactory的泛型類型中提取到注解類型。注意:若沒有指定泛型(沒有指定注解類型)就拋出異常②:該工廠類支持的類型們③:對于支持的每個類型,均注冊一個Printer/Parser

重點在于步驟③,AnnotationPrinterConverter和AnnotationParserConverter均是一個ConditionalGenericConverter轉(zhuǎn)換器,底層實現(xiàn)實際委托給AnnotationFormatterFactory去完成,所以說對AnnotationFormatterFactory的理解格外的重要,還好上篇文章對它已經(jīng)做了詳盡分析,點擊這里電梯直達。

下面以AnnotationPrinterConverter為例觀其源碼:

①:該轉(zhuǎn)換器只負責(zé)將fieldType類型轉(zhuǎn)換為String類型②:只有fieldType上標注有指定的這個注解,此轉(zhuǎn)換器才會生效③:轉(zhuǎn)換邏輯。這種緩存式處理邏輯很是常見,其實最核心的代碼往往只有一句,本處就是它:this.annotationFormatterFactory.getPrinter(...)。獲取到合適的Printer,然后適配為PrinterConverter從而完成最終的convert轉(zhuǎn)換動作

說明:PrinterConverter和ParserConverter在本系列前面文章已介紹,相關(guān)內(nèi)容可出門左拐在本系列內(nèi)很容易找到AnnotationParserConverter的實現(xiàn)邏輯如出一轍,這里就不再啰嗦了。

FormattingConversionService它實現(xiàn)了FormatterRegistry接口的所有接口方法,但是它并未提供一些默認行為。換句話講:實現(xiàn)了所有的組件注冊/管理的能力,但并沒有“幫你”注冊任何組件,所以還不具備能夠直接提供服務(wù)的條件,若要使用還需“人工干預(yù)”放些組件進去才行。

一般來講,對于這種情況一般在外部再包一層 DefaultXXX來提供默認服務(wù)是一種對開發(fā)者十分友好的解決方案,Spring也是這么干的,下面來看看DefaultFormattingConversionService為我們默認注冊了哪些基礎(chǔ)組件,提供了哪些能力呢。

DefaultFormattingConversionService

默認的格式化器轉(zhuǎn)換服務(wù),該默認行為適用于大多數(shù)應(yīng)用程序?qū)Ω袷交?、轉(zhuǎn)換器的需求。

繼承自FormattingConversionService,這個默認行為是為該實例而設(shè)計的,但為了方便使用,它對外暴露了其static靜態(tài)方法addDefaultFormatters(),這個設(shè)計方式同DefaultConversionService暴露了靜態(tài)方法addDefaultConverters()如出一轍。

默認注冊了哪些組件?

對于一個默認的Service服務(wù),最關(guān)心的當(dāng)屬它提供了哪些能力。換句話講:它默認幫我們注冊了哪些組件呢?

要回答這個問題可不能靠“背答案”,方式方法其實非常的簡單,爬進去它的源碼處一看便知:

①:雖然說本類(其實是父類)實現(xiàn)了EmbeddedValueResolverAware接口,但構(gòu)造時依舊可以指定占位符處理器StringValueResolver,當(dāng)然一般情況下傳入null即可②:調(diào)用DefaultConversionService的靜態(tài)方法,把默認的轉(zhuǎn)換器們都注冊進來。那么,默認到底注冊了哪些轉(zhuǎn)換器呢?DefaultConversionService.addDefaultConverters(this)該靜態(tài)方法其實是本系列前面文章所講的內(nèi)容,這里A哥順道也貼在這吧:

③:若registerDefaultFormatters為true就添加默認的格式化器們,一般來講,此值都為true。那么,默認到底注冊了哪些格式化器呢?

①:對@NumberFormat注解提供支持,格式化數(shù)字(Currency、數(shù)字、百分數(shù)等)

②:對JSR 354錢幣類型javax.money.CurrencyUnit、Monetary等類型提供支持。一般情況下,用不著,所以此part不會被真的注冊

③:對JSR-310日期時間的格式化提供支持。這里使用到了其專用的注冊器DateTimeFormatterRegistrar統(tǒng)一操作

④、⑤:第4、5步是互斥操作,若有Jota-Time就提供對它的支持而不觸發(fā)java.util.Date的注冊器,否則使用后者注冊器。

注意:你以為④、⑤是真的互斥嗎?難道導(dǎo)入了joda-time的包后java.util.Date相關(guān)模塊就失效了?很明顯不是這樣的,讓你“放心”的地方在于JodaTimeFormatterRegistrar注冊器內(nèi)部包含了java.util.Date格式化器的注冊關(guān)系,因此一切都還得到xxxRegistrar里去看才能揭曉。

總之,DefaultFormattingConversionService作為默認的格式化轉(zhuǎn)換服務(wù),它是DefaultConversionService的超集,在其基礎(chǔ)上擴展了格式化器,格式化注解支持等相關(guān)能力。在Spring環(huán)境下,大多數(shù)情況使用都是它而非DefaultConversionService。

現(xiàn)在,對FormatterRegistry類一個籠統(tǒng)的認識,知道它默認給注冊了哪些組件,支持哪些功能,但是細節(jié)部分還不清晰。比如說:支持哪些數(shù)據(jù)類型?支持哪些格式?這些都藏在相應(yīng)的xxxRegistrar里~

FormatterRegistrar:注冊員

registrar:登記員;注冊主任。

xxxRegistrar它是一種“倒排”思想的設(shè)計體現(xiàn),能達到高內(nèi)聚的效果。Spring、Spring Boot慣用的“伎倆”,譬如你隨便一搜就能看能看到很多很多:

FormatterRegistrar代表的是格式化器注冊員接口,接口定義:

 
 
 
 
  1. public interface FormatterRegistrar { 
  2.  void registerFormatters(FormatterRegistry registry); 

接口方法含義:將Converter和Formatter注冊進FormatterRegistry注冊中心里,至于注冊哪些組件由各子類自行管理和負責(zé),而非Registry注冊中心主動去編排。這是一種倒排設(shè)計思想,能夠很好的達到高內(nèi)聚的目的。

注意:雖然存在ConverterRegistry和FormatterRegistry兩個接口,但只有FormatterRegistrar而 沒有 ConverterRegistrar哦該接口有三個實現(xiàn)類:

見名之意,每個實現(xiàn)子類都維護著自己分內(nèi)之事,邊界十分清晰。

DateFormatterRegistrar:Date注冊員

提供對java.util.Date、java.util.Calendar、long類型的日期時間的注冊支持。

接口方法實現(xiàn)如下:

①:添加常規(guī)轉(zhuǎn)換器,支持DateToLong、DateToCalendar、LongToCalendar等基礎(chǔ)轉(zhuǎn)換能力②:若有個性化指定格式化器,那就給Calendar專門使用。當(dāng)然,大多數(shù)情況下并不會這么做,這步邏輯是為了向后兼容性而考慮而已,一般可忽略③:添加@DateTimeFormat注解的解析支持

代碼示例

下面介紹DateFormatterRegistrar注冊員的使用示例。

普通使用方式

最常規(guī)的轉(zhuǎn)換,Date、Long、Calendar等日期時間類型似乎是可以互轉(zhuǎn)的。

 
 
 
 
  1. @Test 
  2. public void test1() { 
  3.     FormattingConversionService conversionService = new FormattingConversionService(); 
  4.     // 注冊員負責(zé)添加格式化器以支持Date系列的轉(zhuǎn)換 
  5.     new DateFormatterRegistrar().registerFormatters((FormatterRegistry) conversionService); 
  6.  
  7.     // 1、普通使用 
  8.     long currMills = System.currentTimeMillis(); 
  9.     System.out.println("當(dāng)前時間戳:" + currMills); 
  10.     // Date -> Calendar 
  11.     System.out.println(conversionService.convert(new Date(currMills), Calendar.class)); 
  12.     // Long ->  Date 
  13.     System.out.println(conversionService.convert(currMills, Date.class)); 
  14.     // Calendar -> Long 
  15.     Calendar calendar = Calendar.getInstance(TimeZone.getDefault()); 
  16.     calendar.setTimeInMillis(currMills); 
  17.     System.out.println(conversionService.convert(calendar, Long.class)); 

運行程序,輸出:

 
 
 
 
  1. 當(dāng)前時間戳:1612741385457 
  2. java.util.GregorianCalendar[time=1612741385457 ... 
  3. Mon Feb 08 07:43:05 CST 2021 
  4. 1612741385457 

完美。

注解使用方式

使用更高級的注解方式,如@DateTimeFormat

 
 
 
 
  1. // 準備一個Java Bean: 
  2. @Data 
  3. @AllArgsConstructor 
  4. class Son { 
  5.  
  6.     @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) 
  7.     private Date birthday; 
  8.  

測試代碼:

 
 
 
 
  1. @Test 
  2. public void test1() { 
  3.     FormattingConversionService conversionService = new FormattingConversionService(); 
  4.     // 重要:重要:重要:注冊基礎(chǔ)的轉(zhuǎn)換能力 
  5.     DefaultConversionService.addDefaultConverters((ConverterRegistry) conversionService); 
  6.     // 注冊員負責(zé)添加格式化器以支持Date系列的轉(zhuǎn)換 
  7.     new DateFormatterRegistrar().registerFormatters((FormatterRegistry) conversionService); 
  8.  
  9.     // 1、注解使用 
  10.     Son son = new Son(new Date()); 
  11.     // 輸出:將Date類型輸出為Long類型 
  12.     System.out.println(conversionService.convert(son.getBirthday(), Long.class)); 
  13.     // 輸出:將String烈性輸入為Date類型 
  14.     // System.out.println(conversionService.convert("2021-02-12", Date.class)); // 報錯 
  15.     System.out.println(conversionService.convert(1613034123709L, Date.class)); 

運行程序,輸出:

 
 
 
 
  1. 1613034230018 
  2. Thu Feb 11 17:02:03 CST 2021 

完美。實現(xiàn)了Long類型 <-> Date類型的互轉(zhuǎn)。

可能有同學(xué)會問了,為毛"2021-02-12"就不能convert到Date類型呢?這個原因,額,嗯,哼,若你看了上篇文章 的話,這將不會是個問題。

當(dāng)然,在實際使用中,更多的情況是String -> Date的轉(zhuǎn)換case,怎么破?有兩個辦法:

回味本系列前面文章,因為前面有講了不止一次

關(guān)注后面文章。因為此case過于常見,后面(特別是在Spring MVC下使用)依舊會重點提及

總結(jié)

本文重點是想經(jīng)由FormatterRegistry注冊中心,引述出Spring常用的Registrar注冊員設(shè)計思想,它是一種面向?qū)ο缶幊趟枷氲捏w現(xiàn),是不是比面向過程優(yōu)雅很多呢?本文以DateTimeFormatterRegistrar為示例進行了打樣,可以看到Spring在API抽象這塊著實是非常優(yōu)秀的,擴展性和方便性兼具,這個度把握得絕佳,或許這也算是設(shè)計美學(xué)吧。


分享名稱:Spring的Registrar倒排思想送給你
當(dāng)前地址:http://www.5511xx.com/article/dpeogce.html