MessageSourceAware
一庞瘸、基本信息
?? 作者 - Lex ?? 博客 - 我的CSDN ?? 文章目錄 - 所有文章 ?? 源碼地址 - MessageSourceAware源碼
二、接口描述
MessageSourceAware
接口赠叼,主要用于對象希望被注入MessageSource
擦囊。MessageSource
是Spring中用于國際化(i18n)的接口,它提供了從不同的消息資源(例如:屬性文件)獲取消息的方法嘴办。使用MessageSource
瞬场,我們可以為應(yīng)用程序提供國際化的消息支持。
三涧郊、接口源碼
MessageSourceAware
是 Spring 框架自 1.1.1 開始引入的一個(gè)核心接口贯被。實(shí)現(xiàn)MessageSourceAware
接口的對象會在Spring容器中被自動注入一個(gè)MessageSource
實(shí)例。
/**
* 任何希望被通知運(yùn)行其中的MessageSource(通常是ApplicationContext)的對象需要實(shí)現(xiàn)的接口。
*
* 注意彤灶,MessageSource通常也可以作為bean引用傳遞
* (到任意的bean屬性或構(gòu)造函數(shù)參數(shù))看幼,因?yàn)樗趹?yīng)用上下文中通常是以"name"為messageSource的bean定義的。
*
* 作者: Juergen Hoeller, Chris Beams
* 版本: 1.1.1
* 參見: ApplicationContextAware
*/
public interface MessageSourceAware extends Aware {
/**
* 設(shè)置此對象運(yùn)行的MessageSource幌陕。
* 此方法在常規(guī)bean屬性被填充之后調(diào)用诵姜,但在初始化回調(diào)(如InitializingBean的afterPropertiesSet或自定義的init-method)之前調(diào)用。
* 此方法在ApplicationContextAware的setApplicationContext方法之前被調(diào)用搏熄。
*
* @param messageSource 此對象要使用的消息源
*/
void setMessageSource(MessageSource messageSource);
}
四棚唆、主要功能
-
自動注入
- 當(dāng)一個(gè)bean實(shí)現(xiàn)了
MessageSourceAware
接口,并且被Spring容器管理時(shí)搬卒,Spring將會自動調(diào)用該bean的setMessageSource
方法瑟俭,傳入當(dāng)前應(yīng)用上下文的MessageSource
實(shí)例。
- 當(dāng)一個(gè)bean實(shí)現(xiàn)了
-
國際化支持
- 通過
MessageSourceAware
契邀,beans可以獲得對MessageSource
的訪問權(quán)摆寄,從而可以根據(jù)不同的地區(qū)和語言獲取相應(yīng)的消息。這對于需要顯示不同語言的錯(cuò)誤消息坯门、UI標(biāo)簽或其他用戶面向的文本的beans特別有用微饥。
- 通過
-
簡化配置
- 雖然我們可以通過常規(guī)的依賴注入方法將
MessageSource
注入到beans中,但MessageSourceAware
提供了一種更加自動化和明確的方法古戴,特別是當(dāng)我們的bean需要在初始化過程的特定階段獲得MessageSource
時(shí)欠橘。
- 雖然我們可以通過常規(guī)的依賴注入方法將
五、最佳實(shí)踐
首先來看看啟動類入口现恼,上下文環(huán)境使用AnnotationConfigApplicationContext
(此類是使用Java注解來配置Spring容器的方式)肃续,構(gòu)造參數(shù)我們給定了一個(gè)MyConfiguration
組件類。然后從Spring上下文中獲取一個(gè)MyMessageSourceAware
類型的bean叉袍,最后調(diào)用getMessage
方法始锚。
public class MessageSourceAwareApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfiguration.class);
MyMessageSourceAware messageSourceAware = context.getBean(MyMessageSourceAware.class);
messageSourceAware.getMessage();
}
}
這里使用@Bean
注解,定義了兩個(gè)Bean喳逛,是為了確保 MyMessageSourceAware
瞧捌,MessageSource
被 Spring 容器執(zhí)行。其中ResourceBundleMessageSource
是 Spring 框架中用于國際化(i18n)的一個(gè)具體實(shí)現(xiàn)润文。它為應(yīng)用程序提供了從屬性文件中讀取國際化消息的能力姐呐。
@Configuration
public class MyConfiguration {
@Bean
public MyMessageSourceAware myMessageSourceAware(){
return new MyMessageSourceAware();
}
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("i18n/messages");
return messageSource;
}
}
MyMessageSourceAware
類使用MessageSourceAware
接口來自動獲得對MessageSource
的引用。這個(gè)引用可以用來根據(jù)不同的語言或地區(qū)檢索國際化的消息典蝌。然后利用注入的MessageSource
曙砂,從屬性文件中檢索并打印兩個(gè)國際化的消息,一個(gè)是英文的骏掀,另一個(gè)是簡體中文的鸠澈。
public class MyMessageSourceAware implements MessageSourceAware {
private MessageSource messageSource;
@Override
public void setMessageSource(MessageSource messageSource) {
this.messageSource = messageSource;
}
public void getMessage() {
System.out.println("English:"+messageSource.getMessage("greeting", null, Locale.ENGLISH));
System.out.println("中文:"+messageSource.getMessage("greeting", null, Locale.SIMPLIFIED_CHINESE));
}
}
運(yùn)行結(jié)果發(fā)現(xiàn)乔夯,MyMessageSourceAware
類已成功從屬性文件中獲取了國際化消息。
English:Hello!
中文:我們好
六款侵、時(shí)序圖
sequenceDiagram
Title: EnvironmentAware時(shí)序圖
participant MessageSourceAwareApplication
participant AnnotationConfigApplicationContext
participant AbstractApplicationContext
participant DefaultListableBeanFactory
participant AbstractBeanFactory
participant DefaultSingletonBeanRegistry
participant AbstractAutowireCapableBeanFactory
participant ApplicationContextAwareProcessor
participant MyMessageSourceAware
MessageSourceAwareApplication->>AnnotationConfigApplicationContext:AnnotationConfigApplicationContext(componentClasses)<br>創(chuàng)建上下文
AnnotationConfigApplicationContext->>AbstractApplicationContext:refresh()<br>刷新上下文
AbstractApplicationContext->>AbstractApplicationContext:finishBeanFactoryInitialization(beanFactory)<br>初始化Bean工廠
AbstractApplicationContext->>DefaultListableBeanFactory:preInstantiateSingletons()<br>實(shí)例化單例
DefaultListableBeanFactory->>AbstractBeanFactory:getBean(name)<br>獲取Bean
AbstractBeanFactory->>AbstractBeanFactory:doGetBean(name,requiredType,args,typeCheckOnly)<br>執(zhí)行獲取Bean
AbstractBeanFactory->>DefaultSingletonBeanRegistry:getSingleton(beanName,singletonFactory)<br>獲取單例Bean
DefaultSingletonBeanRegistry-->>AbstractBeanFactory:getObject()<br>獲取Bean實(shí)例
AbstractBeanFactory->>AbstractAutowireCapableBeanFactory:createBean(beanName,mbd,args)<br>創(chuàng)建Bean
AbstractAutowireCapableBeanFactory->>AbstractAutowireCapableBeanFactory:doCreateBean(beanName,mbd,args)<br>執(zhí)行Bean創(chuàng)建
AbstractAutowireCapableBeanFactory->>AbstractAutowireCapableBeanFactory:initializeBean(beanName,bean,mbd)<br>負(fù)責(zé)bean的初始化
AbstractAutowireCapableBeanFactory->>AbstractAutowireCapableBeanFactory:applyBeanPostProcessorsBeforeInitialization(existingBean, beanName)<br>調(diào)用前置處理器
AbstractAutowireCapableBeanFactory->>ApplicationContextAwareProcessor:postProcessBeforeInitialization(bean,beanName)<br>觸發(fā)Aware處理
ApplicationContextAwareProcessor->>ApplicationContextAwareProcessor:invokeAwareInterfaces(bean)<br>執(zhí)行Aware回調(diào)
ApplicationContextAwareProcessor->>MyMessageSourceAware:setMessageSource(messageSource)<br>設(shè)置messageSource
AbstractAutowireCapableBeanFactory-->>AbstractBeanFactory:返回Bean對象
AbstractBeanFactory-->>DefaultListableBeanFactory:返回Bean對象
AnnotationConfigApplicationContext-->>MessageSourceAwareApplication:初始化完成
七末荐、源碼分析
首先來看看啟動類入口,上下文環(huán)境使用AnnotationConfigApplicationContext
(此類是使用Java注解來配置Spring容器的方式)新锈,構(gòu)造參數(shù)我們給定了一個(gè)MyConfiguration
組件類缠借。然后從Spring上下文中獲取一個(gè)MyMessageSourceAware
類型的bean亥至,最后調(diào)用getMessage
方法桑李。
public class MessageSourceAwareApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfiguration.class);
MyMessageSourceAware messageSourceAware = context.getBean(MyMessageSourceAware.class);
messageSourceAware.getMessage();
}
}
在org.springframework.context.annotation.AnnotationConfigApplicationContext#AnnotationConfigApplicationContext
構(gòu)造函數(shù)中宵统,執(zhí)行了三個(gè)步驟,我們重點(diǎn)關(guān)注refresh()
方法
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
this();
register(componentClasses);
refresh();
在org.springframework.context.support.AbstractApplicationContext#refresh
方法中拳缠,我們重點(diǎn)關(guān)注一下finishBeanFactoryInitialization(beanFactory)
這方法會對實(shí)例化所有剩余非懶加載的單列Bean對象墩新,其他方法不是本次源碼閱讀的重點(diǎn)暫時(shí)忽略。
@Override
public void refresh() throws BeansException, IllegalStateException {
// ... [代碼部分省略以簡化]
// 步驟1. Initialize message source for this context.
initMessageSource();
// 步驟2. Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// ... [代碼部分省略以簡化]
}
我們來到org.springframework.context.support.AbstractApplicationContext#refresh
方法中的步驟1窟坐,在org.springframework.context.support.AbstractApplicationContext#initMessageSource
方法中海渊,這個(gè)方法確保Spring應(yīng)用上下文總是有一個(gè)MessageSource
bean可用,無論是否明確定義了它哲鸳。如果用戶沒有定義臣疑,它會提供一個(gè)默認(rèn)實(shí)現(xiàn)。這意味著在Spring上下文中徙菠,我們總是可以安全地調(diào)用getMessage()
讯沈,因?yàn)榭倳幸粋€(gè)MessageSource
可用。
protected void initMessageSource() {
// 獲取Bean工廠
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 檢查是否已經(jīng)存在名為MESSAGE_SOURCE_BEAN_NAME的bean
if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
// 如果存在婿奔,則獲取該bean
this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
// 如果當(dāng)前MessageSource具有層次結(jié)構(gòu)并且沒有設(shè)置父MessageSource
if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
if (hms.getParentMessageSource() == null) {
// 設(shè)置父上下文作為父MessageSource(如果之前沒有注冊過父MessageSource)
hms.setParentMessageSource(getInternalParentMessageSource());
}
}
// ... [代碼部分省略以簡化]
}
else {
// 如果不存在MESSAGE_SOURCE_BEAN_NAME的bean缺狠,則創(chuàng)建一個(gè)DelegatingMessageSource并注冊到上下文
// 使用DelegatingMessageSource以便能夠處理getMessage調(diào)用
DelegatingMessageSource dms = new DelegatingMessageSource();
dms.setParentMessageSource(getInternalParentMessageSource());
this.messageSource = dms;
beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
// ... [代碼部分省略以簡化]
}
}
我們來到org.springframework.context.support.AbstractApplicationContext#refresh
方法中的步驟2,在org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization
方法中萍摊,會繼續(xù)調(diào)用DefaultListableBeanFactory
類中的preInstantiateSingletons
方法來完成所有剩余非懶加載的單列Bean對象挤茄。
/**
* 完成此工廠的bean初始化,實(shí)例化所有剩余的非延遲初始化單例bean记餐。
*
* @param beanFactory 要初始化的bean工廠
*/
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// ... [代碼部分省略以簡化]
// 完成所有剩余非懶加載的單列Bean對象驮樊。
beanFactory.preInstantiateSingletons();
}
在org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons
方法中薇正,主要的核心目的是預(yù)先實(shí)例化所有非懶加載的單例bean片酝。在Spring的上下文初始化完成后,該方法會被觸發(fā)挖腰,以確保所有單例bean都被正確地創(chuàng)建并初始化雕沿。其中getBean(beanName)
是此方法的核心操作。對于容器中定義的每一個(gè)單例bean猴仑,它都會調(diào)用getBean
方法审轮,這將觸發(fā)bean的實(shí)例化肥哎、初始化及其依賴的注入。如果bean之前沒有被創(chuàng)建過疾渣,那么這個(gè)調(diào)用會導(dǎo)致其被實(shí)例化和初始化篡诽。
public void preInstantiateSingletons() throws BeansException {
// ... [代碼部分省略以簡化]
// 循環(huán)遍歷所有bean的名稱
for (String beanName : beanNames) {
getBean(beanName);
}
// ... [代碼部分省略以簡化]
}
在org.springframework.beans.factory.support.AbstractBeanFactory#getBean()
方法中,又調(diào)用了doGetBean
方法來實(shí)際執(zhí)行創(chuàng)建Bean的過程榴捡,傳遞給它bean的名稱和一些其他默認(rèn)的參數(shù)值杈女。此處,doGetBean
負(fù)責(zé)大部分工作吊圾,如查找bean定義达椰、創(chuàng)建bean(如果尚未創(chuàng)建)、處理依賴關(guān)系等项乒。
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
在org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
方法中啰劲,首先檢查所請求的bean是否是一個(gè)單例并且已經(jīng)創(chuàng)建。如果尚未創(chuàng)建檀何,它將創(chuàng)建一個(gè)新的實(shí)例蝇裤。在這個(gè)過程中,它處理可能的異常情況频鉴,如循環(huán)引用猖辫,并確保返回的bean是正確的類型。這是Spring容器bean生命周期管理的核心部分砚殿。
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
// ... [代碼部分省略以簡化]
// 開始創(chuàng)建bean實(shí)例
if (mbd.isSingleton()) {
// 如果bean是單例的啃憎,我們會嘗試從單例緩存中獲取它
// 如果不存在,則使用lambda創(chuàng)建一個(gè)新的實(shí)例
sharedInstance = getSingleton(beanName, () -> {
try {
// 嘗試創(chuàng)建bean實(shí)例
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// ... [代碼部分省略以簡化]
}
});
// 對于某些bean(例如FactoryBeans)似炎,可能需要進(jìn)一步處理以獲取真正的bean實(shí)例
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// ... [代碼部分省略以簡化]
// 確保返回的bean實(shí)例與請求的類型匹配
return adaptBeanInstance(name, beanInstance, requiredType);
}
在org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton()
方法中辛萍,主要負(fù)責(zé)從單例緩存中獲取一個(gè)已存在的bean實(shí)例,或者使用提供的ObjectFactory
創(chuàng)建一個(gè)新的實(shí)例羡藐。這是確保bean在Spring容器中作為單例存在的關(guān)鍵部分贩毕。
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
// 斷言bean名稱不能為空
Assert.notNull(beanName, "Bean name must not be null");
// 同步訪問單例對象緩存,確保線程安全
synchronized (this.singletonObjects) {
// 從緩存中獲取單例對象
Object singletonObject = this.singletonObjects.get(beanName);
// 如果緩存中沒有找到
if (singletonObject == null) {
// ... [代碼部分省略以簡化]
try {
// 使用工廠創(chuàng)建新的單例實(shí)例
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// ... [代碼部分省略以簡化]
}
catch (BeanCreationException ex) {
// ... [代碼部分省略以簡化]
}
finally {
// ... [代碼部分省略以簡化]
}
// ... [代碼部分省略以簡化]
}
// 返回單例對象
return singletonObject;
}
}
在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean()
方法中仆嗦,主要的邏輯是調(diào)用 doCreateBean
辉阶,這是真正進(jìn)行 bean 實(shí)例化、屬性填充和初始化的地方瘩扼。這個(gè)方法會返回新創(chuàng)建的 bean 實(shí)例谆甜。
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// ... [代碼部分省略以簡化]
try {
// 正常的bean實(shí)例化、屬性注入和初始化集绰。
// 這里是真正進(jìn)行bean創(chuàng)建的部分规辱。
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
// 記錄bean成功創(chuàng)建的日志
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
// ... [代碼部分省略以簡化]
}
catch (Throwable ex) {
// ... [代碼部分省略以簡化]
}
}
在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
方法中,initializeBean
方法是bean初始化栽燕,確保bean是完全配置和準(zhǔn)備好的罕袋。
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// 聲明一個(gè)對象改淑,后續(xù)可能用于存放初始化后的bean或它的代理對象
Object exposedObject = bean;
// ... [代碼部分省略以簡化]
try {
// ... [代碼部分省略以簡化]
// bean初始化
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
// ... [代碼部分省略以簡化]
}
// 返回創(chuàng)建和初始化后的bean
return exposedObject;
}
在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean
方法中,如果條件滿足(即 bean 不是合成的)浴讯,那么它會調(diào)用 applyBeanPostProcessorsBeforeInitialization
方法朵夏。這個(gè)方法是 Spring 生命周期中的一個(gè)關(guān)鍵點(diǎn),它會遍歷所有已注冊的 BeanPostProcessor
實(shí)現(xiàn)榆纽,并調(diào)用它們的 postProcessBeforeInitialization
方法侍郭。這允許我們和內(nèi)部處理器在 bean 初始化之前對其進(jìn)行修改或執(zhí)行其他操作。
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
// ... [代碼部分省略以簡化]
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
// ... [代碼部分省略以簡化]
return wrappedBean;
}
在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInitialization
方法中掠河,遍歷每一個(gè) BeanPostProcessor
的 postProcessBeforeInitialization
方法都有機(jī)會對bean進(jìn)行修改或增強(qiáng)
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
在org.springframework.context.support.ApplicationContextAwareProcessor#postProcessBeforeInitialization
方法中亮元,在這個(gè)方法的實(shí)現(xiàn)特別關(guān)注那些實(shí)現(xiàn)了 "aware" 接口的 beans,并為它們提供所需的運(yùn)行環(huán)境信息唠摹。
@Override
@Nullable
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware ||
bean instanceof ApplicationStartupAware)) {
return bean;
}
// ... [代碼部分省略以簡化]
invokeAwareInterfaces(bean);
return bean;
}
在org.springframework.context.support.ApplicationContextAwareProcessor#invokeAwareInterfaces
方法中爆捞,用于處理實(shí)現(xiàn)了"Aware"接口的beans。這些接口使得beans能夠被自動"感知"并獲得對其運(yùn)行環(huán)境或特定依賴的引用勾拉,而不需要顯式地進(jìn)行查找或注入煮甥。
private void invokeAwareInterfaces(Object bean) {
// ... [代碼部分省略以簡化]
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
// ... [代碼部分省略以簡化]
}
最后執(zhí)行到我們自定義的邏輯中,MyMessageSourceAware
類使用MessageSourceAware
接口來自動獲得對MessageSource
的引用藕赞。這個(gè)引用可以用來根據(jù)不同的語言或地區(qū)檢索國際化的消息成肘。然后利用注入的MessageSource
,從屬性文件中檢索并打印兩個(gè)國際化的消息斧蜕,一個(gè)是英文的双霍,另一個(gè)是簡體中文的。
public class MyMessageSourceAware implements MessageSourceAware {
private MessageSource messageSource;
@Override
public void setMessageSource(MessageSource messageSource) {
this.messageSource = messageSource;
}
public void getMessage() {
System.out.println("English:"+messageSource.getMessage("greeting", null, Locale.ENGLISH));
System.out.println("中文:"+messageSource.getMessage("greeting", null, Locale.SIMPLIFIED_CHINESE));
}
}
八批销、注意事項(xiàng)
-
明確的配置
- 確保我們的Spring上下文中有一個(gè)
MessageSource
bean洒闸,通常命名為“messageSource”。雖然Spring提供了一個(gè)默認(rèn)的均芽,但為了滿足自定義需求丘逸,我們可能需要明確地配置它。
- 確保我們的Spring上下文中有一個(gè)
-
生命周期時(shí)機(jī)
-
MessageSourceAware
的setMessageSource
方法在常規(guī)屬性設(shè)置之后和初始化方法(如InitializingBean
的afterPropertiesSet
或任何自定義的init方法)之前被調(diào)用掀宋。確保我們的bean不在其生命周期的早期階段(例如深纲,在構(gòu)造函數(shù)中)期望使用MessageSource
。
-
-
文件位置和命名
- 如果我們使用
ResourceBundleMessageSource
或類似的機(jī)制劲妙,確保我們的屬性文件位于類路徑上湃鹊,并且與我們在MessageSource
配置中指定的basename匹配。
- 如果我們使用
-
編碼問題
- 屬性文件默認(rèn)使用ISO-8859-1編碼是趴。如果我們的消息包含非此編碼的字符(例如中文涛舍、俄文等)澄惊,確保使用Unicode轉(zhuǎn)義或正確設(shè)置文件的編碼唆途。
-
父子上下文
- 在使用Spring的父子上下文(例如富雅,在Web應(yīng)用中)時(shí),子上下文可以訪問父上下文中的
MessageSource
肛搬,但反之則不行没佑。確保我們在正確的上下文中配置了MessageSource
。
- 在使用Spring的父子上下文(例如富雅,在Web應(yīng)用中)時(shí),子上下文可以訪問父上下文中的
-
避免硬編碼
- 盡量不要在代碼中硬編碼消息鍵或默認(rèn)消息温赔。最好在屬性文件中管理它們蛤奢,這樣在未來需要更改或添加新的語言支持時(shí),我們不需要修改代碼陶贼。
-
默認(rèn)消息
- 當(dāng)使用
MessageSource
檢索消息時(shí)啤贩,考慮提供一個(gè)默認(rèn)消息。這可以在未找到特定消息時(shí)提供一個(gè)后備拜秧,避免拋出異常痹屹。
- 當(dāng)使用
八、總結(jié)
最佳實(shí)踐總結(jié)
-
啟動類
- 在
MessageSourceAwareApplication
類中枉氮,使用了AnnotationConfigApplicationContext
來啟動Spring應(yīng)用志衍。這個(gè)上下文是專為基于Java注解的配置而設(shè)計(jì)的。啟動時(shí)聊替,它加載了MyConfiguration
配置類楼肪,并從上下文中獲取了MyMessageSourceAware
bean,隨后調(diào)用了getMessage
方法顯示消息惹悄。
- 在
-
配置類
-
MyConfiguration
是一個(gè)基于Java的Spring配置類春叫,其中定義了兩個(gè)bean:MyMessageSourceAware
和messageSource
。messageSource
bean是一個(gè)ResourceBundleMessageSource
實(shí)例泣港,用于從i18n/messages
基本名稱的屬性文件中讀取國際化消息象缀。
-
-
實(shí)現(xiàn)MessageSourceAware接口
-
MyMessageSourceAware
類實(shí)現(xiàn)了MessageSourceAware
接口,這意味著Spring容器會自動注入一個(gè)MessageSource
實(shí)例到這個(gè)bean中爷速。這是通過setMessageSource
方法完成的央星。
-
-
消息檢索
- 在
MyMessageSourceAware
的getMessage
方法中,使用了注入的MessageSource
來檢索和打印兩種語言的國際化消息:英文和簡體中文惫东。
- 在
-
運(yùn)行結(jié)果
- 當(dāng)應(yīng)用程序執(zhí)行時(shí)莉给,它成功地從對應(yīng)的屬性文件中獲取并顯示了英文和簡體中文的國際化消息。
源碼分析總結(jié)
-
應(yīng)用啟動
- 我們從
MessageSourceAwareApplication
啟動應(yīng)用廉沮,使用AnnotationConfigApplicationContext
初始化Spring容器颓遏,并加載MyConfiguration
配置。
- 我們從
-
容器初始化
- 在
AnnotationConfigApplicationContext
的構(gòu)造函數(shù)中滞时,執(zhí)行了register
和refresh
方法叁幢,其中refresh
是最重要的,它觸發(fā)了容器的初始化和bean的創(chuàng)建過程坪稽。
- 在
-
消息源初始化
- 在容器刷新的
refresh
方法中曼玩,首先確保了一個(gè)MessageSource
bean存在鳞骤,這是通過initMessageSource
方法完成的。如果沒有明確定義MessageSource
bean黍判,Spring會提供一個(gè)默認(rèn)實(shí)現(xiàn)豫尽,確保應(yīng)用上下文總是有一個(gè)可用。
- 在容器刷新的
-
bean實(shí)例化
- 隨后顷帖,在
refresh
方法中美旧,通過調(diào)用finishBeanFactoryInitialization
方法,容器開始實(shí)例化所有非延遲加載的單例bean贬墩。
- 隨后顷帖,在
-
Bean的生命周期
- 在bean的創(chuàng)建過程中榴嗅,Spring容器會確保所有的生命周期回調(diào)都被正確地執(zhí)行,其中最重要的是
BeanPostProcessors
陶舞。這些處理器提供了一個(gè)插件機(jī)制录肯,允許我們在bean的初始化前后執(zhí)行自定義的邏輯。
- 在bean的創(chuàng)建過程中榴嗅,Spring容器會確保所有的生命周期回調(diào)都被正確地執(zhí)行,其中最重要的是
-
處理Aware接口
-
ApplicationContextAwareProcessor
是一個(gè)特殊的BeanPostProcessor
吊说,它關(guān)心那些實(shí)現(xiàn)了"Aware"接口的beans论咏。對于實(shí)現(xiàn)了MessageSourceAware
的beans,該處理器會自動注入應(yīng)用上下文的MessageSource
颁井。
-
-
消息檢索
- 在我們的
MyMessageSourceAware
類中厅贪,已經(jīng)成功地獲取了MessageSource
的引用。然后雅宾,我們調(diào)用其getMessage
方法养涮,從屬性文件中檢索并打印兩個(gè)國際化的消息。
- 在我們的