程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> 深入理解Spring系列之四:BeanDefinition裝載前奏曲,

深入理解Spring系列之四:BeanDefinition裝載前奏曲,

編輯:JAVA綜合教程

深入理解Spring系列之四:BeanDefinition裝載前奏曲,


  框架的源碼分析,有些代碼可以暫時忽略,如Spring如何進行XML模式校驗的、XML解析的細節等,這些代碼可以在了解了整體的原理之後,再做針對性的分析,關注重點內容即可,切記在一開始就去深挖每個細節,這樣不僅會耗費很長時間,而且容易陷入某個坑裡出不來。

  以《深入理解Spring系列之一:開篇》示例中的ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationgContext.xml")為入口,進入源碼內部,ClassPathXmlApplicationContext類圖如下。

ClassPathXmlApplicationContext類圖

ClassPathXmlApplicationContext有多個構造方法,跟蹤代碼可以發現,最終使用的是下面這個方法,

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
      throws BeansException {
    super(parent);
    setConfigLocations(configLocations);
    if (refresh) {
      refresh();
    }
}

方法的參數很容易理解,configLocations指Spring的xml配置文件;refresh指是否需要刷新,這個refresh決定了是否進行bean解析、注冊及實例化;parent指父ApplicationContext。setConfigLocations方法就是設置框架要加載的資源文件的位置。進入refresh方法,這個方法繼承自AbstractApplicationContext,所以具體實現在AbstractApplicationContext類中,具體代碼如下。

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
      //容器預先准備,記錄容器啟動時間和標記
      prepareRefresh();
      //創建bean工廠,裡面實現了BeanDefinition的裝載
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
      //配置bean工廠的上下文信息,如類裝載器等
      prepareBeanFactory(beanFactory);
      try {
        //在BeanDefinition被裝載後,提供一個修改BeanFactory的入口
        postProcessBeanFactory(beanFactory);
        //在bean初始化之前,提供對BeanDefinition修改入口,PropertyPlaceholderConfigurer在這裡被調用
        invokeBeanFactoryPostProcessors(beanFactory);
        //注冊各種BeanPostProcessors,用於在bean被初始化時進行攔截,進行額外初始化操作
        registerBeanPostProcessors(beanFactory);
        //初始化MessageSource
        initMessageSource();
        //初始化上下文事件廣播
        initApplicationEventMulticaster();
        //模板方法
        onRefresh();
        //注冊監聽器
        registerListeners();
        //初始化所有未初始化的非懶加載的單例Bean
finishBeanFactoryInitialization(beanFactory);
        //發布事件通知
        finishRefresh();
      }catch (BeansException ex) {
        if (logger.isWarnEnabled()) {
          logger.warn("Exception encountered during context initialization - " +
              "cancelling refresh attempt: " + ex);
        }
        // Destroy already created singletons to avoid dangling resources.
        destroyBeans();
        // Reset 'active' flag.
        cancelRefresh(ex);
        // Propagate exception to caller.
        throw ex;
      }finally {
        // Reset common introspection caches in Spring's core, since we
        // might not ever need metadata for singleton beans anymore...
        resetCommonCaches();
      }
    }
  }

這個方法裡面就是IOC容器初始化的大致步驟了。上面步驟的第二步完成了BeanDefinition的裝載,進入obtainFreshBeanFactory方法,這個方法的具體實現也在AbstractApplicationContext類中,代碼如下所示。

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    refreshBeanFactory();
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
      logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
    }
    return beanFactory;
}

這裡面主要關注refreshBeanFactory方法,這個方法在AbstractApplicationContext類中並未實現,具體實現在子類AbstractRefreshableApplicationContext中,代碼如下。

protected final void refreshBeanFactory() throws BeansException {
    if (hasBeanFactory()) {
      destroyBeans();
closeBeanFactory();
    }
    try {
      DefaultListableBeanFactory beanFactory = createBeanFactory();
      beanFactory.setSerializationId(getId());
      customizeBeanFactory(beanFactory);
      loadBeanDefinitions(beanFactory);
      synchronized (this.beanFactoryMonitor) {
        this.beanFactory = beanFactory;
      }
    }
    catch (IOException ex) {
      throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
    }
}

這個方法使用了final修飾,也就是不能被重寫了。首先檢查BeanFactory是否已經存在,如果存在則銷毀並關閉,然後新建一個BeanFactory,其實就是一個DefaultListableBeanFactory,這個DefaultListableBeanFactory就是《深入理解Spring系列之一:開篇》說的那個。然後進行BeanFactory的屬性設置,設置是否允許重寫BeanDefinition、是否允許循環引用,接著loadBeanDefinitions方法就是BeanDefinition載入的入口了,這個方法在AbstractRefreshableApplicationContext本類中並未實現,具體在其子類中實現,根據用途不同有多個實現子類,下一篇內容將分析基於最基本的解析xml方式的AbstractXmlApplicationContext類中的實現。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved