1. 程式人生 > >spring原始碼學習筆記-初始化(三)-BeanFactory

spring原始碼學習筆記-初始化(三)-BeanFactory

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

refresh()方法中在上篇obtainFreshBeanFactory()方法建立了beanfactory物件,之後的程式碼就開始是對beanFactory物件的一些處理,BeanFactory相關的一些內容也是spring的核心內容。

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

一、首先是prepareBeanFactory(beanFactory),主要是做了一些beanFactory的初始化工作,因為這個方法比較長,我們分成4部分來看,

第1部分程式碼:

[java] view plaincopyprint?
  1. beanFactory.setBeanClassLoader(getClassLoader());  
  2. beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver());  
  3. beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this));  
  4. beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(
    this));  
  5. beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);  
  6. beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);  
  7. beanFactory.ignoreDependencyInterface(MessageSourceAware.class);  
  8. beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);  
  9. beanFactory.registerResolvableDependency(BeanFactory.
    class, beanFactory);  
  10. beanFactory.registerResolvableDependency(ResourceLoader.classthis);  
  11. beanFactory.registerResolvableDependency(ApplicationEventPublisher.classthis);  
  12. beanFactory.registerResolvableDependency(ApplicationContext.classthis);  
beanFactory.setBeanClassLoader(getClassLoader());
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver());
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this));
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
  • 第1行設定beanFactory的classLoader為當前context的classLoader
  • 第2行設定beanFactory的表示式語言處理器,spring3增加了表示式語言的支援,預設可以使用#{bean.xxx}的形式來呼叫相關屬性值。
  • 第3行為beanFactory增加了一個預設的propertyEditor,這個主要是對bean的屬性等設定管理的一個工具,以後再做詳細分析。
  • 第4行添加了一個處理aware相關介面的beanPostProcessor擴充套件,主要是使用beanPostProcessor的postProcessBeforeInitialization()前置處理方法實現aware相關介面的功能,aware介面是用來給bean注入一些資源的介面,例如實現BeanFactoryAware的Bean在初始化後,Spring容器將會注入BeanFactory的例項相應的還有ApplicationContextAware、ResourceLoaderAware、ServletContextAware等等。
  • 第5-8行設定了幾個忽略自動裝配的介面,預設只有BeanFactoryAware被忽略,其他的都要自行設定,這裡設定了ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware和ApplicationContextAware。
  • 第9-12行設定了幾個自動裝配的特殊規則,如果是BeanFactory型別,則注入beanFactory物件,如果是ResourceLoader、ApplicationEventPublisher、ApplicationContext型別則注入當前物件(applicationContext物件)。

第2部分程式碼:

[java] view plaincopyprint?
  1. if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {  
  2.     beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));  
  3.     beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));  
  4. }  
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
    beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
    beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
  • 這部分判斷是否定義了名為loadTimeWeaver的bean,如果定義了則新增loadTimeWeaver功能的beanPostProcessor擴充套件,並且建立一個臨時的classLoader來讓其處理真正的bean。spring的loadTimeWeaver主要是通過 instrumentation 的動態位元組碼增強在裝載期注入依賴。具體這部分還沒有很好的理解,暫時標記一下以後再專門研究看看。

第3部分程式碼:

[java] view plaincopyprint?
  1. if (!beanFactory.containsBean(SYSTEM_PROPERTIES_BEAN_NAME)) {  
  2.     Map systemProperties;  
  3. try {  
  4.         systemProperties = System.getProperties();  
  5.     } catch (AccessControlException ex) {  
  6.         systemProperties = new ReadOnlySystemAttributesMap() {  
  7. protected String getSystemAttribute(String propertyName) {  
  8. try {  
  9. return System.getProperty(propertyName);  
  10.                 } catch (AccessControlException ex) {  
  11. if (logger.isInfoEnabled()) {  
  12.                         logger.info("Not allowed to obtain system property [" + propertyName + "]: " +  
  13.                                 ex.getMessage());  
  14.                     }  
  15. returnnull;  
  16.                 }  
  17.             }  
  18.         };  
  19.     }  
  20.     beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, systemProperties);  
  21. }  
if (!beanFactory.containsBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
    Map systemProperties;
    try {
        systemProperties = System.getProperties();
    } catch (AccessControlException ex) {
        systemProperties = new ReadOnlySystemAttributesMap() {
            protected String getSystemAttribute(String propertyName) {
                try {
                    return System.getProperty(propertyName);
                } catch (AccessControlException ex) {
                    if (logger.isInfoEnabled()) {
                        logger.info("Not allowed to obtain system property [" + propertyName + "]: " +
                                ex.getMessage());
                    }
                    return null;
                }
            }
        };
    }
    beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, systemProperties);
}


這部分首先判斷是否定義了名為systemProperties的bean,如果沒有則載入系統獲取當前系統屬性System.getProperties()並註冊為一個單例bean。假如有AccessControlException許可權異常則建立一個ReadOnlySystemAttributesMap物件,可以看到建立時重寫了getSystemAttribute()方法,檢視ReadOnlySystemAttributesMap的程式碼可以得知在呼叫get方法的時候會去呼叫這個方法來獲取key對應的物件,當獲取依舊有許可權異常AccessControlException的時候則返回null。

第4部分程式碼:

[java] view plaincopyprint?
  1. if (!beanFactory.containsBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {  
  2.     Map<String,String> systemEnvironment;  
  3. try {  
  4.         systemEnvironment = System.getenv();  
  5.     } catch (AccessControlException ex) {  
  6.         systemEnvironment = new ReadOnlySystemAttributesMap() {  
  7. protected String getSystemAttribute(String variableName) {  
  8. try {  
  9. return System.getenv(variableName);  
  10.                 } catch (AccessControlException ex) {  
  11. if (logger.isInfoEnabled()) {  
  12.                         logger.info("Not allowed to obtain system environment variable [" + variableName + "]: " +  
  13.                                 ex.getMessage());  
  14.                     }  
  15. returnnull;  
  16.                 }  
  17.             }  
  18.         };  
  19.     }  
  20.     beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, systemEnvironment);  
  21. }  
if (!beanFactory.containsBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
    Map<String,String> systemEnvironment;
    try {
        systemEnvironment = System.getenv();
    } catch (AccessControlException ex) {
        systemEnvironment = new ReadOnlySystemAttributesMap() {
            protected String getSystemAttribute(String variableName) {
                try {
                    return System.getenv(variableName);
                } catch (AccessControlException ex) {
                    if (logger.isInfoEnabled()) {
                        logger.info("Not allowed to obtain system environment variable [" + variableName + "]: " +
                                ex.getMessage());
                    }
                    return null;
                }
            }
        };
    }
    beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, systemEnvironment);
}
  • 這部分和上面一部分類似,只不過由系統屬性改為了系統環境變數,異常處理方式等也和上面一部分一樣。這兩部分都是為spring內部提供系統資訊的支撐bean。

二、prepareBeanFactory()方法呼叫之後,是一個try-catch程式碼塊,如果有BeanException異常產生則會停止refresh並且銷燬已建立的資源,現在看程式碼塊裡的第一行postProcessBeanFactory(beanFactory)

postProcessBeanFactory()方法,預設方法體是空的,主要是用來擴充套件beanfactory的,擴充套件點是在bean等配置都已經載入但還沒有進行例項化的時候。

例如上面說到的aware相關介面自動裝配設定,假如是web專案,使用的是spring的webApplicationcontext,這時需要一些ServletContextAware相關的自動裝配忽略及配置等,就需要在webApplicationContext裡重寫這個方法來實現相應功能。