1. 程式人生 > >spring原始碼學習筆記-初始化(五)-MessageSource/事件監聽器

spring原始碼學習筆記-初始化(五)-MessageSource/事件監聽器

轉自http://www.sandzhang.com/blog/2011/04/07/spring-study-notes-initialization-5/

refresh()方法中在上篇看完了對PostProcessors的處理,這篇繼續往下看。

注:refresh()的程式碼就不再次列舉了,請看spring原始碼中AbstractApplicationContext類。

一、initMessageSource(),這個方法是對spring的MessageSource初始化,程式碼如下:


[java] view plaincopyprint?
  1. ConfigurableListableBeanFactory beanFactory = getBeanFactory(); 
  2. if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) { 
  3.     //第1部分
  4. else
  5.     //第2部分
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
    //第1部分
}
else {
    //第2部分
}

  • 首先獲取beanFactory物件,然後判斷是否定義了名為messageSource的localbean,如果有則執行第1部分,否則執行第2部分,分別來看兩部分程式碼
    注:localbean實際上就是指查詢的時候不會去parent查詢這個bean,只從當前beanfactory去查詢,很多地方有這個就不一一註明了

第1部分:


[java] view plaincopyprint?
  1. this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class); 
  2. if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) { 
  3.     HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource; 
  4.     if (hms.getParentMessageSource() == null) { 
  5.         hms.setParentMessageSource(getInternalParentMessageSource()); 
  6.     } 
  7. if (logger.isDebugEnabled()) { 
  8.     logger.debug("Using MessageSource [" + this.messageSource + "]"); 
this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
    HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
    if (hms.getParentMessageSource() == null) {
        hms.setParentMessageSource(getInternalParentMessageSource());
    }
}
if (logger.isDebugEnabled()) {
    logger.debug("Using MessageSource [" + this.messageSource + "]");
}

  • 第1行獲取名為messageSource的bean賦值給當前ApplicationContext物件的messageSource屬性
  • 第2行判斷如果當前ApplicationContext的parent不為null;並且messageSource物件繼承了HierarchicalMessageSource介面則進行如下處理:
        進行判斷如果messageSource的parentMessageSource為空,則設定為getInternalParentMessageSource()方法的返回值。getInternalParentMessageSource()方法的程式碼也很簡單
        (getParent() instanceof AbstractApplicationContext) ? ((AbstractApplicationContext) getParent()).messageSource : getParent()
        如果當前ApplicationContext的parent物件是AbstractApplicationContext或其子類型別則返回它的messageSource,否則直接返回其parent物件
  • 最後是列印一行debug級別日誌表示當前應用的messageSource

第2部分:

[java] view plaincopyprint?
  1. DelegatingMessageSource dms = new DelegatingMessageSource(); 
  2. dms.setParentMessageSource(getInternalParentMessageSource()); 
  3. this.messageSource = dms; 
  4. beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource); 
  5. if (logger.isDebugEnabled()) { 
  6.     logger.debug("Unable to locate MessageSource with name '" + MESSAGE_SOURCE_BEAN_NAME + 
  7.             "': using default [" + this.messageSource + "]"); 
DelegatingMessageSource dms = new DelegatingMessageSource();
dms.setParentMessageSource(getInternalParentMessageSource());
this.messageSource = dms;
beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
if (logger.isDebugEnabled()) {
    logger.debug("Unable to locate MessageSource with name '" + MESSAGE_SOURCE_BEAN_NAME +
            "': using default [" + this.messageSource + "]");
}

  • 第1行建立一個DelegatingMessageSource物件dms
  • 第2行類似上面,設定dms的parentMessageSource為getInternalParentMessageSource()返回值
  • 第3行設定當前ApplicationContext的messageSource屬性為dms
  • 第4行把這個物件註冊一個名為messageSource的單例bean
  • 列印一行debut日誌表示無使用者定義messageSource,使用預設
二、緊接著處理完messageSource的初始化後下一行程式碼:initApplicationEventMulticaster(),主要是對spring的事件監聽器的管理器的初始話,程式碼如下:
[java] view plaincopyprint?
  1. ConfigurableListableBeanFactory beanFactory = getBeanFactory(); 
  2. if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) { 
  3.     this.applicationEventMulticaster = 
  4.             beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class); 
  5.     if (logger.isDebugEnabled()) { 
  6.         logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]"); 
  7.     } 
  8. else
  9.     this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory); 
  10.     beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster); 
  11.     if (logger.isDebugEnabled()) { 
  12.         logger.debug("Unable to locate ApplicationEventMulticaster with name '"
  13.                 APPLICATION_EVENT_MULTICASTER_BEAN_NAME + 
  14.                 "': using default [" + this.applicationEventMulticaster + "]"); 
  15.     } 
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
    this.applicationEventMulticaster =
            beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
    if (logger.isDebugEnabled()) {
        logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
    }
}
else {
    this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
    beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
    if (logger.isDebugEnabled()) {
        logger.debug("Unable to locate ApplicationEventMulticaster with name '" +
                APPLICATION_EVENT_MULTICASTER_BEAN_NAME +
                "': using default [" + this.applicationEventMulticaster + "]");
    }
}

  • 和messageSource的處理類似,首先取得beanFactory物件,
  • 判斷如果使用者主動定義了applicationEventMulticaster的bean,則把這個bean設定給applicationEventMulticaster屬性
  • 如果沒有則初始話一個預設的SimpleApplicationEventMulticaster,註冊bean並賦值給對應屬性
  • 不同情況分別列印不同的日誌,原始碼中的日誌列印最好也稍微注意一下有個印象,這樣在看spring的日誌時會更清晰

三、接下來是一個模板方法onRefresh(),第一篇中提到過這個是在處理messageSource、applicationEventMulticaster等特殊bean後,普通單例bean沒初始話之前,為ApplicationContext子類提供擴充套件去處理一些類似的特殊bean。

    舉個例子AbstractRefreshableWebApplicationContext、GenericWebApplicationContext、StaticWebApplicationContext中都有一個themeSource,這個就要放在這個方法裡去初始化。這個themeSource是spring的主題功能,可以實現根據不同主題載入不同資原始檔等功能。

四、上面處理了事件監聽器的管理器初始化,現在開始做時間監聽器的註冊:registerListeners(),這個方法的程式碼如下:


[java] view plaincopyprint?
  1. for (ApplicationListener listener : getApplicationListeners()) { 
  2.     getApplicationEventMulticaster().addApplicationListener(listener); 
  3. String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false); 
  4. for (String lisName : listenerBeanNames) { 
  5.     getApplicationEventMulticaster().addApplicationListenerBean(lisName); 
for (ApplicationListener listener : getApplicationListeners()) {
    getApplicationEventMulticaster().addApplicationListener(listener);
}
 
String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
for (String lisName : listenerBeanNames) {
    getApplicationEventMulticaster().addApplicationListenerBean(lisName);
}

  • 上面3行是處理當前ApplicationContext中的靜態特殊監聽器集合,迴圈呼叫applicationEventMulticaster的addApplicationListener()方法註冊到applicationEventMulticaster中
  • 後面的一部分首先取出所有型別為ApplicationListener的bean的name集合,然後迴圈呼叫applicationEventMulticaster的addApplicationListenerBean()方法註冊到applicationEventMulticaster中
  • 注意上面兩個註冊方法的不同,分別會註冊到applicationEventMulticaster.defaultRetriever的不同集合中

本篇分別看到了messageSource、applicationEventMulticaster和applicationListener以及中間提到的主題themeSource的初始化,這裡主要介紹初始話,所以後續再對spring的這幾個功能模組做分別詳細的分析。