Spring消息代碼理解

 
一、簡介
1、Spring消息體系的定義:
①消息取得接口:MessageSource、HierarchicalMessageSource
②消息參數接口:MessageSourceResolvable
2、Spring消息體系的實現:
①消息取得:AbstractMessageSource、ResourceBundleMessageSource、ReloadableResourceBundleMessageSource、StaticMessageSource
②消息參數:DefaultMessageSourceResolvable、FieldError、ObjectError
3、Spring消息體系的使用:
①ApplicationContext、MessageSourceAware
二、Spring消息體系的定義
1、MessageSource:
定義個三個getMessage操作:
  • String getMessage(String code, Object[] args, String defaultMessage, Locale locale);
  • String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException;
  • String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;
Spring爲一個取得消息的操作,提供了三個方法,細化了取消息操作的不同需求。一種提供默認消息,不報異常;一種不提供默認消息,報NoSuchMessageException;一種使用MessageSourceResolvable封裝需要的參數,雖然封裝的參數中提供了默認消息,但爲防止提供了無效的默認消息,還是報了NoSuchMessageException。
2、HierarchicalMessageSource:
繼承MessageSource接口,添加了兩個操作:
  • void setParentMessageSource(MessageSource parent);
  • MessageSource getParentMessageSource();
Spring通過這兩個方法提供了一種實現MessageSource層次的定義
3、MessageSourceResolvable:
爲了方便MessageSource的使用,Spring定義了取消息使用的參數對象,提供了三個操作:
  • public String[] getCodes();
  • public Object[] getArguments();
  • public String getDefaultMessage();
4、接口定義中的智慧
①MessageSource與HierarchicalMessageSource接口的分離,爲兩個不同的目的都定義了清晰的接口。雖然了Spring的MessageSource的實現都繼承與HierarchicalMessageSource,當時因爲MessageSource接口的存在,可以使ApplicationContext接口直接提供一個標準的取得消息的方法集,而不用去關心消息體系的具體實現。
②提供MessageSourceResolvable接口,方便消息的使用。取得消息時不需要自己組織多個參數,而是直接將一個MessageSourceResolvable的實現傳入即可。
③MessageSourceResolvable接口爲什麼不提供getLocal()操作?國際化應該是與業務實現無關,不應該是由業務實現去考慮。最好通過配置,或其他方法自動取得。
三、Spring消息體系的實現
1、AbstractMessageSource
①實現了HierarchicalMessageSource接口,提供了MessageSource的一個基本的抽象實現,並提供protected abstract MessageFormat resolveCode(String code, Locale locale);方法,留給子類自己決定自己的國際化實現。
②提供的屬性:
  • private boolean useCodeAsDefaultMessage = false;
定義當沒有提供Default Message時,是否使用Message Code作爲Default Message。
  • private boolean alwaysUseMessageFormat = false;
當沒有消息參數時,是否還是使用MessageFormat。當消息中包含一些需要MessageFormat特殊處理的逃逸字符時,需要設置爲true。
③實現操作祥解:
  • void setParentMessageSource(MessageSource parent);
  • MessageSource getParentMessageSource();
④實現了消息的層次操作,並將父MessageSource保存。
  • String getMessage(String code, Object[] args, String defaultMessage, Locale locale);
  • String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException;
  • String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;
所有取得消息的操作都有getMessageInternal()方法實現。根據默認消息取得默認消息時,使用renderDefaultMessage()方法。無默認消息根據useCodeAsDefaultMessage屬性,取得默認消息時使用getDefaultMessage()方法。
⑤getMessageInternal()方法的實現:
  • 無消息參數,且alwaysUseMessageFormat爲false時,調用resolveCodeWithoutArguments()方法直接取得消息。其實在resolveCodeWithoutArguments()方法的實現中還是使用MessageFormat,所以Spring建議在子類中覆蓋resolveCodeWithoutArguments()方法。
  • 否則,先調用resolveArguments()方法將參數中的MessageSourceResolvable實例轉化爲對應的消息,然後調用resolveCode()取得MessageFormat,之後使用MessageFormat處理消息。
  • 當沒有找到消息時,調用getMessageFromParent()方法,從父MessageSource中查找消息。
⑥cachedMessageFormats
考慮到多數DefaultMessage都是一些同樣錯誤消息,所以Spring使用一個HashMap—cachedMessageFormats緩存了DefaultMessage的MessageFormat。
2、StaticMessageSource
繼承AbstractMessageSource類,提供了最簡單的MessageSource的實現。提供了兩個操作:
  • addMessage()將消息編號和對應的MessageFormat保存於一個HashMap中。
  • resolveCode()根據消息編號和Local從HashMap中取得對應的MessageFormat。
3、ResourceBundleMessageSource
繼承AbstractMessageSource類,實現了BeanClassLoaderAware接口,提供了一種使用Resource Bundle的Message Source的實現。
  • basenames屬性
可以指定一個或一組查找message的文件,可包含目錄和Classpath。
resolveCodeWithoutArguments()覆蓋了父類的對應方法,實現了直接從配置文件讀取message並直接返回,不使用MessageFormat。
  • resolveCode()
調用getResourceBundle()取得對應的ResourceBundle,然後通過取得的ResourceBundle取得對應的MessageFormat。
  • ResourceBundleMessageSource中的緩存實現。
  • ResourceBundle緩存
針對每一個Basename都緩存一個不同Local的HashMap。
  • MessageFormat緩存
針對每一個ResourceBundle都緩存一個Code的Map,其中緩存了一個Code的不同Local的MessageFormat。
4、ReloadableResourceBundleMessageSource
繼承AbstractMessageSource類,實現了ResourceLoaderAware接口,提供了一種可以Reload的MessageSource的實現。
通過自己實現的PropertiesPersister和PropertiesHolder,跳過ResoureBundle的緩存機制,實現一個可以刷新的MessageSoruce。
四、Spring消息體系的使用
1.ApplicationContext
實現了MessageSource接口,將getMessage的調用轉發給實際的MessageSource的實現。
2.MessageSourceAware
當Spring的IOC容器發現實現了此接口的實例,就會將ApplicationContext注入到此實例中。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章