SpringIOC容器初始化過程總結

最近學習了SpringIOC的源碼。將自己的學習成果總結如下。

SpringIOC

IOC容器:所有上層框架bean實例依賴環境

BeanFactory簡介

BeanFactory : bean工廠提供bean的實例

beanFactory在早期設計中就只是一個提供bean實例對象工廠,通過各種條件定位到我們所需要的Bean,作爲頂層接口定義了IOC容器的基本規範。

我們可以看一下BeanFactory這個接口中聲明的屬性及方法

  • String FACTORY_BEAN_PREFIX = “&”;

    這是BeanFactory接口中的唯一一個屬性。這個地方需要衍生出一個概念,Spring 中有兩種類型的bean。一種是普通的JavaBean,另一種是工廠bean(FactoryBean,需要實現Spring定義的FactoryBean接口),這兩種bean都由SpringIOC容器來進行管理。FactoryBean和javaBean不同的地方在於通過BeanFactory類的getBean方法直接獲取到的並不是FactoryBean的實例而是 FactoryBean中的方法getObject返回的對象。假如我們需要獲取FactoryBean的實例。我們需要在getBean方法獲取實例的時候在參數前加入"&"符號就行了。即BeanFactory中的FACTORY_BEAN_PREFIX屬性。

  • Object getBean(String name) throws BeansException;

    通過名稱獲取bean實例,之後會詳細講解這個方法

  • T getBean(String name, Class requiredType) throws BeansException;

    通過註釋 Behaves the same as {@link #getBean(String)}, but provides a measure of type 我們可以看出來這個方法行爲和getBean(String name)相同,但是提供了類型的度量。不同於上面的getBean方法的是。如果我們獲取到的bean和傳入的類型不一致,則會拋出BeanNotOfRequiredTypeException異常。

  • T getBean(Class requiredType) throws BeansException;

    返回與所需類型匹配的單個bean的實例

  • Object getBean(String name, Object… args) throws BeansException;

    args參數,用於使用顯式參數創建bean實例
    *(僅在創建新實例而不是檢索現有實例時應用)

  • T getBean(Class requiredType, Object… args) throws BeansException;

    同理獲取給定類型的bean,args參數在創建實例時使用

  • boolean containsBean(String name);

    是否包含該bean

  • boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

    這個bean是否是單例

  • boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

    是否getBean方法每次都返回不同的實例

  • boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

    檢查具有給定名稱的bean是否與指定類型匹配。這裏插一點內容。ResolvableType是Spring4.0之後推出的一個類。不同於下面這個方法的是。Class是一種類型,但它本身不具有類型的屬性。ResolvableType爲所有的java類型提供了統一的數據結構以及API,換句話說,一個ResolvableType對象就對應着一種java類型。我們可以通過ResolvableType對象獲取類型攜帶的信息。例如父類型,接口類型,Type對象到class對象的轉換等。在Spring框架中需要反射的時候,爲了不丟失信息,通常使用ResolvableType來進行封裝類型。

  • boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

    檢查具有給定名稱的bean是否與指定類型匹配。

  • Class<?> getType(String name) throws NoSuchBeanDefinitionException;

    獲取具有給定名稱的bean的類型。

  • String[] getAliases(String name);

    返回別名,如果沒有則返回空數組。在getBean方法中,所有的別名都指向同一個Bean。如果傳入的參數是別名,則同時返回原始Bean的名稱,並且Bean的名稱作爲數組中的第一個元素。

逐步演進發展成這樣:

我們再分別分析BeanFactory的子接口。

ListableBeanFactory

這個接口聲明瞭一些獲取多個Bean的方法。在BeanFactory中,getBean方法獲取的都是單個Bean。大致看一下ListableBeanFactory中聲明的方法

通過方法名我們可以很清晰的看到每個方法的作用,這裏引入了一個新的名稱:BeanDefinition。

BeanDefinition

BeanDefinition接口繼承了AttributeAccessor,BeanMetadataElement接口。

AttributeAccessor接口定義了最基本的對任意對象的元數據的修改或者獲取。基本接口如下:

BeanMetadataElement 接口提供了一個getResource()方法,用來傳輸一個可配置的源對象。getResource方法返回此元數據元素的配置源對象。

看完兩個接口以後,我們再來看BeanDefinition的聲明

一個BeanDefinition描述了一個bean的實例,包括屬性值,構造方法參數值和繼承自它的類的更多信息。BeanDefinition僅僅是一個最簡單的接口,主要功能是允許BeanFactoryPostProcessor例如PropertyPlaceHolderConfigure能夠檢索並修改屬性值和別的bean的元數據。BeanDefinition就是Spring中的Bean,我們定義的Bean會轉化成爲一個個BeanDefinition存在於Spring的BeanFactory當中。注意幾個比較重要的點:

  • setAutowireCandidate方法

    設置該bean是否可以注入到其他的Bean當中。只對根據類型注入有效。如果根據名稱注入,即使這裏設置的爲false。也可以注入成功。

  • setPrimary 方法

    當同一個接口有多個實現的時候,Spring會優先選擇設置primary爲true的bean

  • BeanFactoryPostProcessor

    對已經加載好的BeanDefinition進行處理。SpringIOC容許BeanFactoryPostProcessor在容器實際實例化任何bean之前讀取配置的元數據。例如我們常用的${property}這樣的表達式,實際上就是對配置信息進行替換。這樣使得配置解耦。具體的實現邏輯就是在BeanFactoryPostProcessor相關的實現類中的postProcessBeanFactory方法中實現的。

  • methodOverrides

    方法重寫的持有者,記錄lookup-method,replaced-method元素。

HierarchicalBeanFactory

接下來繼續看HierarchicalBeanFactory接口,實現該接口的BeanFactory具有繼承關係。

AutowireCapableBeanFactory接口,實現該接口的BeanFactory可以自動裝配bean。

BeanFactory的默認實現類DefaultListableBeanFactory。隨着Spring的擴展,DefaultListableBeanFactory無法滿足各種各樣的情況下Bean的獲取及生產。然後又逐步演進出了ApllicationContext。SpringIOC的過程中,本質上是ApplicationContext持有了一個DefaultListableBeanFactory。這個類很重要,他同時實現了BeanDefinitionRegistry接口。BeanDefinitionRegistry接口的主要作用是向註冊表中註冊BeanDefinition實例。完成註冊的過程。

DefaultListableBeanFactory

DefaultListableBeanFactory是BeanFactory的默認實現類,實現了BeanFactory下層的三個接口。

ApllicationContext

ApllicationContext的架構圖如下所示:

IOC容器初始化過程

資源加載 -> 資源解析 -> BeanDefinition註冊 -> getBean()獲取bean的實例

ContextLoaderListener

傳統的Spring項目中,我們需要在web.xml文件中配置如下內容:

org.springframework.web.context.ContextLoaderListener

ContextLoaderListener 繼承自ContextLoader,實現了ServletContextListener接口。

這裏是可以看作是我們Spring在web開發過程中的起點,ContextLoaderListener可以指定在web應用程序啓動時載入IOC容器,正是通過ContextLoader來實現的。ContextLoader來完成實際的WebApplicationContext也就是IOC容器的初始化工作。ServletContextListener接口裏的函數會結合Web容器的生命週期被調用。因爲ServletContextListener是ServletContext的監聽者,如果ServletContext發生變化,會觸發相應的事件,而監聽器一直對事件監聽,如果接受到了變化,就會做出預先設計好的相應動作,由於ServletContext變化而觸發的監聽器的響應有服務器啓動時,servletContext被創建,服務器關閉時,servletContext被銷燬。所以contextLoaderListener的作用是啓動web容器時,讀取在contextConfigLocation中定義的xml文件,自動裝配ApplicationContext的配置信息,併產生WebApplicationContext對象。然後將這個對象放置在ServletContext的屬性裏。這樣我們可以通過servlet獲取到WebApplicationContext對象,並利用這個對象訪問Spring容器管理的bean。

同樣我們還需要在web.xml中配置context-param參數。

contextConfigLocation /WEB-INF/ * -servlet.xml,classpath:conf/applicationContext- * .xml

在ContextLoader的加載過程中,會讀取contextConfigLocation參數的值,然後解析資源配置文件。

代碼調用鏈

接下來我們啓動一個Spring配置的項目,來一步一步的解析IOC容器的初始化過程。

contextInitialized

首先代碼的入口在ContextLoaderListener的contextInitialized方法中,ServletContext創建時會調用該方法。

@Override
public void contextInitialized(ServletContextEvent event) {
   initWebApplicationContext(event.getServletContext());
}

我們可以看到這個方法實際上是調用了contextLoader類裏面的initWebApplicationContext方法。接下來我們點進initWebApplicationContext方法中。

initWebApplicationContext

public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
   if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
      throw new IllegalStateException(
            "Cannot initialize context because there is already a root application context present - " +
            "check whether you have multiple ContextLoader* definitions in your web.xml!");
   }

   Log logger = LogFactory.getLog(ContextLoader.class);
   servletContext.log("Initializing Spring root WebApplicationContext");
   if (logger.isInfoEnabled()) {
      logger.info("Root WebApplicationContext: initialization started");
   }
   long startTime = System.currentTimeMillis();

   try {
      // Store context in local instance variable, to guarantee that
      // it is available on ServletContext shutdown.
      if (this.context == null) {
         this.context = createWebApplicationContext(servletContext);
      }
      if (this.context instanceof ConfigurableWebApplicationContext) {
         ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
         if (!cwac.isActive()) {
            // The context has not yet been refreshed -> provide services such as
            // setting the parent context, setting the application context id, etc
            if (cwac.getParent() == null) {
               // The context instance was injected without an explicit parent ->
               // determine parent for root web application context, if any.
               ApplicationContext parent = loadParentContext(servletContext);
               cwac.setParent(parent);
            }
            configureAndRefreshWebApplicationContext(cwac, servletContext);
         }
      }
      servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

      ClassLoader ccl = Thread.currentThread().getContextClassLoader();
      if (ccl == ContextLoader.class.getClassLoader()) {
         currentContext = this.context;
      }
      else if (ccl != null) {
         currentContextPerThread.put(ccl, this.context);
      }

      if (logger.isDebugEnabled()) {
         logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +
               WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
      }
      if (logger.isInfoEnabled()) {
         long elapsedTime = System.currentTimeMillis() - startTime;
         logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
      }

      return this.context;
   }
   catch (RuntimeException ex) {
      logger.error("Context initialization failed", ex);
      servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
      throw ex;
   }
   catch (Error err) {
      logger.error("Context initialization failed", err);
      servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
      throw err;
   }
}

這個方法裏面有幾個比較重要的方法。首先在ServletContext中找有沒有ApplicationContext存在,如果有則報錯,因爲ServletContext只會初始化一次,ApplicationContext也只會創建一次。接下來我們看createWebApplication(servlet)方法

createWebApplication

在createWebApplication方法中,首先通過datermineContextClass(sc)來確定實現類,如果在web.xml中配置了contextClass參數,值爲webApplicationContext的實現類,則返回配置類的Class。如果沒有配置,則會返回Spring默認的實現類XmlWebApplicationContext。然後生成一個ApplicationContext的對象。

回到initWebApplicaitonContext方法中,因爲XmlWebApplicationContext間接實現了ConfigurableWebApplicationContext接口,所以將會執行configureAndRefreshWebApplicationContext(cwac, servletContext);方法。

configureAndRefreshWebApplicationContext
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
   if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
      // The application context id is still set to its original default value
      // -> assign a more useful id based on available information
      String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);
      if (idParam != null) {
         wac.setId(idParam);
      }
      else {
         // Generate default id...
         wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
               ObjectUtils.getDisplayString(sc.getContextPath()));
      }
   }

   wac.setServletContext(sc);
   String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
   if (configLocationParam != null) {
      wac.setConfigLocation(configLocationParam);
   }

   // The wac environment's #initPropertySources will be called in any case when the context
   // is refreshed; do it eagerly here to ensure servlet property sources are in place for
   // use in any post-processing or initialization that occurs below prior to #refresh
   ConfigurableEnvironment env = wac.getEnvironment();
   if (env instanceof ConfigurableWebEnvironment) {
      ((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
   }

   customizeContext(sc, wac);
   wac.refresh();
}

這個方法我們可以看到會讀取我們前面配置在web.xml文件當中的contextConfigLocation參數,如果沒有配置,默認讀取路徑爲 “/WEB-INF/applicationContext.xml”。這個方法裏面有一個最重要的方法,refresh();這個方法纔是真正的Spring配置工作,具體實現在AbstractApplicationContext當中。接下來會具體講這個方法。

refresh

這個方法是SpringIOC容器初始化的核心,需要一個一個的講解,先大概看一下具有以下的方法。

public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
      // 初始化準備工作
      prepareRefresh();

      // 獲取BeanFactory
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // BeanFactory的預準備工作
      prepareBeanFactory(beanFactory);

      try {
         // beanFactory準備工作完成之後進行的後置處理工作。
         postProcessBeanFactory(beanFactory);

         // 調用BeanFactoryPostProcessor各個實現類的postProcessFactory(factory)方法。
         invokeBeanFactoryPostProcessors(beanFactory);

         // 註冊BeanPostProcessor的實現類
         registerBeanPostProcessors(beanFactory);

         // 初始化當前ApplicationContext的MessageSource
         initMessageSource();

         //初始化ApplicationContext事件廣播器
         initApplicationEventMulticaster();

         // 鉤子方法,在這裏可以初始化一些特殊的bean
         onRefresh();

         // 註冊事件監聽器
         registerListeners();

         // 初始化所有的singleton beans
         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();
      }
   }
}
prepareRefresh

準備工作,記錄下容器的啓動時間,標記爲已啓動狀態,處理配置文件中的佔位符。

protected void prepareRefresh() {
   this.startupDate = System.currentTimeMillis();
   this.closed.set(false);
   this.active.set(true);

   if (logger.isInfoEnabled()) {
      logger.info("Refreshing " + this);
   }

   // Initialize any placeholder property sources in the context environment
   initPropertySources();

   // Validate that all properties marked as required are resolvable
   // see ConfigurablePropertyResolver#setRequiredProperties
   getEnvironment().validateRequiredProperties();

   // Allow for the collection of early ApplicationEvents,
   // to be published once the multicaster is available...
   this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}
obtainFreshBeanFactory

將配置文件解析爲bean的定義,註冊到BeanFactory中。bean還沒有完全初始化,但是具有了一個beanName->beanDefinition的map

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

實現類位於AbstractRefreshableApplicationContext

@Override
protected final void refreshBeanFactory() throws BeansException {
	//如果ApplicationContext中已經加載過了BeanFactory,銷燬所有的Bean並關閉BeanFactory。
	//這裏需要知道,應用中的BeanFactory可以是多個的,檢查的是當前ApplicationContext是否有BeanFactory
   if (hasBeanFactory()) {
      destroyBeans();
      closeBeanFactory();
   }
   try {
  		// 初始化一個DefaultListableBeanFactory。
      DefaultListableBeanFactory beanFactory = createBeanFactory();
      // 將BeanFactory進行序列話
      beanFactory.setSerializationId(getId());
      // 設置BeanFactory的兩個屬性,是否允許Bean覆蓋,是否允許循環引用。
      customizeBeanFactory(beanFactory);
      // 加載Bean到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);
   }
}

通過觀察hasBeanFactory方法我們可以知道,這裏檢查的是當前對象的屬性beanFactory是否被初始化了。所以ApplicationContext繼承自BeanFactory,但本質上是持有了一個DefaultListableBeanFactory的對象。

  • customizeBeanFactory

    protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
    	// 是否允許Bean的定義覆蓋
       if (this.allowBeanDefinitionOverriding != null) {
          beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
       }
       	// 是否允許Bean循環依賴
       if (this.allowCircularReferences != null) {
          beanFactory.setAllowCircularReferences(this.allowCircularReferences);
       }
    }
    

    默認情況下,Spring允許循環依賴。之後會講解Spring如何解決循環依賴的問題。

  • loadBeanDefinitions

    實現類在XmlWebApplicationContext中

    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
       // Create a new XmlBeanDefinitionReader for the given BeanFactory. 
       XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
    
       // Configure the bean definition reader with this context's
       // resource loading environment.
       beanDefinitionReader.setEnvironment(this.getEnvironment());
       beanDefinitionReader.setResourceLoader(this);
       beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
    
       // Allow a subclass to provide custom initialization of the reader,
       // then proceed with actually loading the bean definitions.
       initBeanDefinitionReader(beanDefinitionReader);
       loadBeanDefinitions(beanDefinitionReader);
    }
    

    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); 這一步構造了一個XmlBeanDefinitionReader實例。我們可以看到的是傳入了一個BeanDefinitionRegistry的實現對象beanFactory。在之後的解析過程中,我們所使用的registry就是用的beanFactory。

    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
       String[] configLocations = getConfigLocations();
       if (configLocations != null) {
          for (String configLocation : configLocations) {
             reader.loadBeanDefinitions(configLocation);
          }
       }
    }
    

    這個地方的configLocations實質上就是我們前面在web.xml裏面配置的contextConfigLocation參數。

    接下來我們來看reader.loadBeanDefinitions(configLocation);這個方法。這個方法的實現位於XmlBeanDefinitionReader的父類AbstractBeanDefinitionReader中。經過簡單的調用之後,執行以下代碼:

    public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
    //之前新建對象時會初始化一個ResourceLoader,這裏返回ResourceLoader。
       ResourceLoader resourceLoader = getResourceLoader();
       if (resourceLoader == null) {
          throw new BeanDefinitionStoreException(
                "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
       }
    
       if (resourceLoader instanceof ResourcePatternResolver) {
          // Resource pattern matching available.
          try {
          //獲取資源,這裏返回的就是一個我們配置的xml文件的資源。
             Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
             int loadCount = loadBeanDefinitions(resources);
             if (actualResources != null) {
                for (Resource resource : resources) {
                   actualResources.add(resource);
                }
             }
             if (logger.isDebugEnabled()) {
                logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
             }
             return loadCount;
          }
          catch (IOException ex) {
             throw new BeanDefinitionStoreException(
                   "Could not resolve bean definition resource pattern [" + location + "]", ex);
          }
       }
       else {
          // Can only load single resources by absolute URL.
          Resource resource = resourceLoader.getResource(location);
          int loadCount = loadBeanDefinitions(resource);
          if (actualResources != null) {
             actualResources.add(resource);
          }
          if (logger.isDebugEnabled()) {
             logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
          }
          return loadCount;
       }
    }
    

    我們來看這一步int loadCount = loadBeanDefinitions(resources); 這裏經過簡單的調用之後會進入XmlBeanDefinitionReader的loadBeanDefinitions方法。如下:

    public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
       Assert.notNull(encodedResource, "EncodedResource must not be null");
       if (logger.isInfoEnabled()) {
          logger.info("Loading XML bean definitions from " + encodedResource.getResource());
       }
    	//這裏獲取資源,第一次進來的時候爲null
       Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
       if (currentResources == null) {
       //初始化並賦值給resourcesCurrentlyBeingLoaded
          currentResources = new HashSet<EncodedResource>(4);
          this.resourcesCurrentlyBeingLoaded.set(currentResources);
       }
       if (!currentResources.add(encodedResource)) {
          throw new BeanDefinitionStoreException(
                "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
       }
       try {
          InputStream inputStream = encodedResource.getResource().getInputStream();
          try {
             InputSource inputSource = new InputSource(inputStream);
             if (encodedResource.getEncoding() != null) {
                inputSource.setEncoding(encodedResource.getEncoding());
             }
             return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
          }
          finally {
             inputStream.close();
          }
       }
       catch (IOException ex) {
          throw new BeanDefinitionStoreException(
                "IOException parsing XML document from " + encodedResource.getResource(), ex);
       }
       finally {
          currentResources.remove(encodedResource);
          if (currentResources.isEmpty()) {
             this.resourcesCurrentlyBeingLoaded.remove();
          }
       }
    }
    

這個方法就是簡單的獲取文件流然後調用doLoadBeanDefinitions方法。接下來我們來看一下doLoadBeanDefinitions方法。這個方法依舊在XmlBeanDefinitionReader中

主要只有兩行代碼

// 將資源文件解析爲Document
Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);

接下來我們看registerBeanDefinitions。

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
	 //使用DefaultBeanDefinitionDocumentReader實例化BeanDefinitionDocumentReader
   BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
   // 記錄統計前BeanDefintion的加載個數
   int countBefore = getRegistry().getBeanDefinitionCount();
   // 加載及註冊bean
   documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
   // 記錄本次加載的BeanDefintion個數
   return getRegistry().getBeanDefinitionCount() - countBefore;
}

這裏調用了documentReader的registerBeanDefinitions方法。實現類爲DefaultBeanDefinitionDocumentReader

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
   this.readerContext = readerContext;
   logger.debug("Loading bean definitions");
   Element root = doc.getDocumentElement();
   doRegisterBeanDefinitions(root);
}

走到這一步的時候,資源文件已經變成了一個Element,接下來就是解析這個Element並註冊了。

protected void doRegisterBeanDefinitions(Element root) {
  // BeanDefinitionParserDelegate 用於解析XML bean定義的有狀態委託類。
   BeanDefinitionParserDelegate parent = this.delegate;
   this.delegate = createDelegate(getReaderContext(), root, parent);

   if (this.delegate.isDefaultNamespace(root)) {
   //這裏是解析配置了profile屬性的beans
      String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
      if (StringUtils.hasText(profileSpec)) {
         String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
               profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
         if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
            return;
         }
      }
   }

   preProcessXml(root);
   parseBeanDefinitions(root, this.delegate);
   postProcessXml(root);

   this.delegate = parent;
}
  • BeanDefinitionParserDelegate類提供瞭解析spring配置文件功能,對於默認空間下的元素()在該類內部實現,對於其它命名空間下的元素可以通過綁定NamespaceHandler的方式來實現,針對每個命名空間下的元素提供不同BeanDefinitionParser來實現.
  • preProcessXml和postProcessXml都是空的。鉤子方法。一個類要麼是面向繼承設計,要麼就用final修飾。
  • 判斷是否爲默認的命名空間 。即root的namespaceURI是否爲http://www.springframework.org/schema/beans
  • 假如我們配置了Spring.profiles.active屬性,則會對beans標籤進行解析,是否是當前環境所需要的bean
  • 重點講解DefaultBeanDefinitionDocumentReader的parseBeanDefinitions方法。

parseBeanDefinitions

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
   if (delegate.isDefaultNamespace(root)) {
      NodeList nl = root.getChildNodes();
      for (int i = 0; i < nl.getLength(); i++) {
         Node node = nl.item(i);
         if (node instanceof Element) {
            Element ele = (Element) node;
            if (delegate.isDefaultNamespace(ele)) {
               parseDefaultElement(ele, delegate);
            }
            else {
               delegate.parseCustomElement(ele);
            }
         }
      }
   }
   else {
      delegate.parseCustomElement(root);
   }
}

這裏我們可以看到所有的解析方法都進入了parseDefaultElement(ele, delegate);和 delegate.parseCustomElement(ele);parseDefaultElement方法解析的是,,,

這四個標籤之所以是默認標籤,是因爲他們處於http://www.springframework.org/schema/beans這個namespace下定義的。

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
   if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
      importBeanDefinitionResource(ele);
   }
   else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
      processAliasRegistration(ele);
   }
   else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
      processBeanDefinition(ele, delegate);
   }
   else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
      // recurse
      doRegisterBeanDefinitions(ele);
   }
}

其他的標籤類似於,,,等都會進入parseCustomElement這個方法。

public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
   String namespaceUri = getNamespaceURI(ele);
   NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
   if (handler == null) {
      error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
      return null;
   }
   return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
processBeanDefinition

不同的標籤會有不同的NamespaceHandler來進行解析。我們看一下bean標籤是如何被解析的

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//將<bean/>標籤節點的信息提取出來,然後封裝到一個BeanDefintionHolder中。包含了配置文件中配置的各種屬性了。
   BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
   if (bdHolder != null) {
      bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
      try {
         // Register the final decorated instance.
         BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
      }
      catch (BeanDefinitionStoreException ex) {
         getReaderContext().error("Failed to register bean definition with name '" +
               bdHolder.getBeanName() + "'", ele, ex);
      }
      // Send registration event.
      getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
   }
}

我們來跟進如何解析BeanDefinition的。首先從元素的解析及信息提取開始。也就是 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);方法。我們進入BeanDefinitionDelegate類的parseBeanDefinitionElement方法。如下:

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
//解析id屬性
   String id = ele.getAttribute(ID_ATTRIBUTE);
   //解析name屬性
   String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

//分割name屬性
   List<String> aliases = new ArrayList<String>();
   if (StringUtils.hasLength(nameAttr)) {
      String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
      aliases.addAll(Arrays.asList(nameArr));
   }

   String beanName = id;
   //如果沒有指定id,則設置別名列表的第一個名字作爲beanN啊,e
   if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
      beanName = aliases.remove(0);
      if (logger.isDebugEnabled()) {
         logger.debug("No XML 'id' specified - using '" + beanName +
               "' as bean name and " + aliases + " as aliases");
      }
   }

   if (containingBean == null) {
      checkNameUniqueness(beanName, aliases, ele);
   }

//根據bean標籤的配置創建Beandefinition。
   AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
   if (beanDefinition != null) {
   //如果不存在beanName,則根據Spring中提供的命名規則爲當前bean生成對應的beanName
      if (!StringUtils.hasText(beanName)) {
         try {
            if (containingBean != null) {
               beanName = BeanDefinitionReaderUtils.generateBeanName(
                     beanDefinition, this.readerContext.getRegistry(), true);
            }
            else {
               beanName = this.readerContext.generateBeanName(beanDefinition);
               // Register an alias for the plain bean class name, if still possible,
               // if the generator returned the class name plus a suffix.
               // This is expected for Spring 1.2/2.0 backwards compatibility.
               String beanClassName = beanDefinition.getBeanClassName();
               if (beanClassName != null &&
                     beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
                     !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                  aliases.add(beanClassName);
               }
            }
            if (logger.isDebugEnabled()) {
               logger.debug("Neither XML 'id' nor 'name' specified - " +
                     "using generated bean name [" + beanName + "]");
            }
         }
         catch (Exception ex) {
            error(ex.getMessage(), ele);
            return null;
         }
      }
      String[] aliasesArray = StringUtils.toStringArray(aliases);
      return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
   }

   return null;
}

這個方法主要做了以下幾步

  • 提取元素的id和name屬性

  • 進一步解析其他所有的屬性並統一封裝到AbstractBeanDefinition類型的實例中

  • 如果檢測到bean沒有制定beanName,那麼使用默認規則爲此bean生成beanName

  • 將獲取到的信息封裝到BeanDefinitionHolder的實例中。

    看一下如何封裝到AbstractBeanDefinition當中的。

    public AbstractBeanDefinition parseBeanDefinitionElement(
          Element ele, String beanName, BeanDefinition containingBean) {
    
       this.parseState.push(new BeanEntry(beanName));
    
       String className = null;
       //解析class屬性
       if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
          className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
       }
    
       try {
          String parent = null;
          if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
             parent = ele.getAttribute(PARENT_ATTRIBUTE);
          }
          //創建BeanDefinition並設置類信息。
          AbstractBeanDefinition bd = createBeanDefinition(className, parent);
    
    			//解析bean的各種屬性
          parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
          //設置description
          bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
    			//解析<meta/>	
          parseMetaElements(ele, bd);
          //解析<lookup-method/>	
          parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
           //解析<replaced-method/>	
          parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
    			//解析<constructor-arg/>	
          parseConstructorArgElements(ele, bd);
          //解析<property/>	
          parsePropertyElements(ele, bd);
          //解析<qualifier/>	
          parseQualifierElements(ele, bd);
    
          bd.setResource(this.readerContext.getResource());
          bd.setSource(extractSource(ele));
    
          return bd;
       }
       catch (ClassNotFoundException ex) {
          error("Bean class [" + className + "] not found", ele, ex);
       }
       catch (NoClassDefFoundError err) {
          error("Class that bean class [" + className + "] depends on not found", ele, err);
       }
       catch (Throwable ex) {
          error("Unexpected failure during bean definition parsing", ele, ex);
       }
       finally {
          this.parseState.pop();
       }
    
       return null;
    }
    

可以看到的是這個方法將標籤都解析到AbstractBeanDefinition上了。

  • meta標籤:meta標籤並不會體現在bean的屬性當中,而是需要的時候通過BeanDefinition的getAttribute獲取。
  • lookup-method標籤:Spring動態改變bean裏方法的實現。方法執行返回的對象,使用Spring內原有的這類對象替換,通過改變方法返回值來動態改變方法,內部實現爲使用cglib方法。重新生成子類,重寫配置的方法和返回對象,達到動態改變的效果。這段話看起來有點抽象,我們通常稱爲獲取器注入,我們在lookup-method標籤裏定義的name爲方法名,bean爲返回值對象。
  • replaced-method:方法替換,可以在運行時用新的方法替換現有的方法。與之前的look-up不同的是,replaced-method不但可以動態地替換返回實體bean,而且還能動態地更改原有方法的邏輯。

到這一步,我們已經根據一個bean標籤完成了一個BeanDefinitionHolder實例的創建。我們看一下BeanDefinitionHolder裏面的內容。

回到processBeanDefinition中,當我們完成processBeanDefintion後我們接下來會進行bean的註冊

BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());

public static void registerBeanDefinition(
      BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
      throws BeanDefinitionStoreException {

   // Register bean definition under primary name.
   String beanName = definitionHolder.getBeanName();
   registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

   // Register aliases for bean name, if any.如果還有別名,將別名也註冊
   String[] aliases = definitionHolder.getAliases();
   if (aliases != null) {
      for (String alias : aliases) {
         registry.registerAlias(beanName, alias);
      }
   }
}

顯而易見,這個方法裏面最重要的就是 registry.registerBeanDefinition。結合我們上面的提到的registry就是DefaultListableBeanFactory。接下來我們看DefaultListableBeanFactory的註冊方法registerBeanDefinition。

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
      throws BeanDefinitionStoreException {

   Assert.hasText(beanName, "Bean name must not be empty");
   Assert.notNull(beanDefinition, "BeanDefinition must not be null");

   if (beanDefinition instanceof AbstractBeanDefinition) {
      try {
         ((AbstractBeanDefinition) beanDefinition).validate();
      }
      catch (BeanDefinitionValidationException ex) {
         throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
               "Validation of bean definition failed", ex);
      }
   }

   BeanDefinition oldBeanDefinition;
	//beanDefinitionMap實質上就是DefaultListableBeanFactory持有的一個ConcurrentHashMap
   oldBeanDefinition = this.beanDefinitionMap.get(beanName);
   if (oldBeanDefinition != null) {
   //如果不允許覆蓋,則拋一場
      if (!isAllowBeanDefinitionOverriding()) {
         throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
               "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
               "': There is already [" + oldBeanDefinition + "] bound.");
      }
    //getRole 獲取bean的分類,
    ///Bean角色,
    // int ROLE_APPLICATION = 0;  //應用程序重要組成部分
    // int ROLE_SUPPORT = 1;  //做爲大量配置的一部分(支持、擴展類)
    // int ROLE_INFRASTRUCTURE = 2;  //指內部工作的基礎構造
      else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
         // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
         if (this.logger.isWarnEnabled()) {
            this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
                  "' with a framework-generated bean definition: replacing [" +
                  oldBeanDefinition + "] with [" + beanDefinition + "]");
         }
      }
      else if (!beanDefinition.equals(oldBeanDefinition)) {
         if (this.logger.isInfoEnabled()) {
            this.logger.info("Overriding bean definition for bean '" + beanName +
                  "' with a different definition: replacing [" + oldBeanDefinition +
                  "] with [" + beanDefinition + "]");
         }
      }
      else {
         if (this.logger.isDebugEnabled()) {
            this.logger.debug("Overriding bean definition for bean '" + beanName +
                  "' with an equivalent definition: replacing [" + oldBeanDefinition +
                  "] with [" + beanDefinition + "]");
         }
      }
      this.beanDefinitionMap.put(beanName, beanDefinition);
   }
   else {
   //判斷是否有bean已經開始初始化了
      if (hasBeanCreationStarted()) {
         // Cannot modify startup-time collection elements anymore (for stable iteration)
         synchronized (this.beanDefinitionMap) {
            this.beanDefinitionMap.put(beanName, beanDefinition);
            List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
            updatedDefinitions.addAll(this.beanDefinitionNames);
            updatedDefinitions.add(beanName);
            this.beanDefinitionNames = updatedDefinitions;
            if (this.manualSingletonNames.contains(beanName)) {
               Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
               updatedSingletons.remove(beanName);
               this.manualSingletonNames = updatedSingletons;
            }
         }
      }
      else {
         // Still in startup registration phase  將beanDefinition放入map當中
         this.beanDefinitionMap.put(beanName, beanDefinition);
         // 已經註冊的beanName添加進去
         this.beanDefinitionNames.add(beanName);
         // 從需要手動註冊的bean中刪除
         this.manualSingletonNames.remove(beanName);
      }
      this.frozenBeanDefinitionNames = null;
   }

   if (oldBeanDefinition != null || containsSingleton(beanName)) {
      resetBeanDefinition(beanName);
   }
}

到這一步,bean的解析已經完成了。我們回到refresh方法中。

prepareBeanFactory

設置BeanFactory的類加載器,添加幾個BeanPostProcessor(還未註冊BeanPostProcessor),手動註冊特殊的bean。

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
   // Tell the internal bean factory to use the context's class loader etc.
   //爲ApplicationContext設置類加載器。
   beanFactory.setBeanClassLoader(getClassLoader());
   //設置BeanExpressionResovler SpEL表達式的解析器
   beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
   // 
   beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

   // Configure the bean factory with context callbacks.
   //設置BeanPostProcessor
   beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
   // 自動裝備時忽略以下幾個類
   beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
   beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
   beanFactory.ignoreDependencyInterface(EnvironmentAware.class);

   // BeanFactory interface not registered as resolvable type in a plain factory.
   // MessageSource registered (and found for autowiring) as a bean.
   beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
   beanFactory.registerResolvableDependency(ResourceLoader.class, this);
   beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
   beanFactory.registerResolvableDependency(ApplicationContext.class, this);

   // Detect a LoadTimeWeaver and prepare for weaving, if found.
   if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
      beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
      // Set a temporary ClassLoader for type matching.
      beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
   }

   // Register default environment beans.
   if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
      beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
   }
   if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
      beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
   }
   if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
      beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
   }
}
  • 這裏又新引入了一個概念BeanPostProcessor。BeanPostProcessor可以在Spring容器實例化bean之後,在執行bean的初始化方法前後,添加一些自己的處理邏輯。bean的初始化方法指的是實現了initializingBean接口的afterPropertiesSet方法。或者bean定義時通過init-methode設置的方法。而BeanFactoryPostProcessor我們在上文中有提到過,在spring容器加載了bean的定義文件之後,在bean實例化之前執行的,允許修改bean的屬性,例如將scope從singleton改爲prototype。

看完了xml是如何解析的之後,我們直接進入正題,bean是如何實例化及初始化的。我們想要獲取一個bean通常通過BeanFactory的getBean方法來獲取。finishBeanFactoryInitialization方法通過簡單的鏈式調用之後,也會進入到getBean方法中。getBean調用了doGetBean方法。

doGetBean
protected <T> T doGetBean(
      final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
      throws BeansException {
	//獲取beanName,這裏需要注意兩個點。一種是處理FactoryBean,一種是將別名轉換爲真實的beanName。
   final String beanName = transformedBeanName(name);
   Object bean;

   //檢查緩存中或者實例工廠中是否有對應的實例。
   //因爲在創建單例bean的時候會存在依賴注入的情況,而在創建依賴的時候爲了避免循環依賴,
   //Spring創建bean的原則是不等bean創建完成就會將創建bean的ObjectFactory提早曝光
   //也就是將ObjectFactory加入到緩存中,一旦下個bean創建時候需要依賴上個bean則直接使用ObjectFactory
   Object sharedInstance = getSingleton(beanName);
   // 假如doGetBean方法傳入了args參數,那麼我們不再是獲取bean了,而是重新創建bean
   if (sharedInstance != null && args == null) {
      if (logger.isDebugEnabled()) {
         if (isSingletonCurrentlyInCreation(beanName)) {
            logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
                  "' that is not fully initialized yet - a consequence of a circular reference");
         }
         else {
            logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
         }
      }
      // 這個地方大家看起來可能就會有疑問了,明明已經獲取了sharedInstance,爲什麼還要獲取bean。
      // 這裏其實就是因爲如果是普通的bean,那麼就直接返回sharedInstance了,
      // 如果是FactoryBean,那麼我們返回FactoryBean的getObject對象。除非傳入了&符號,則返回當前對象等。
      bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   }

   else {
      // Fail if we're already creating this bean instance:
      // We're assumably within a circular reference.
      // 假如當前線程已經創建過此beanName的原型的bean。那麼會拋異常。這種情況產生的可能性是因爲循環依賴。
      // 原型模式的情況下,無法解決循環依賴,因爲依賴之後會重新創建對象。A創建B,B創建A。
      if (isPrototypeCurrentlyInCreation(beanName)) {
         throw new BeanCurrentlyInCreationException(beanName);
      }

      // Check if bean definition exists in this factory.
      BeanFactory parentBeanFactory = getParentBeanFactory();
      //如果beanDefinitionMap中沒有這個bean並且父beanFactory存在。則嘗試從父容器中獲取。
      if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
         // Not found -> check parent.
         String nameToLookup = originalBeanName(name);
         if (args != null) {
            // Delegation to parent with explicit args.
            return (T) parentBeanFactory.getBean(nameToLookup, args);
         }
         else {
            // No args -> delegate to standard getBean method.
            return parentBeanFactory.getBean(nameToLookup, requiredType);
         }
      }

      if (!typeCheckOnly) {
      //如果不是僅僅做類型檢查,而是創建bean,則將當前的beanName傳入到一個alreadyCreated的Set集合當中
      //進行記錄
         markBeanAsCreated(beanName);
      }
		//	到這一步就表明已經需要創建bean了。
      try {
      //  將存儲xml配置文件的GenericBeanDefinition轉換爲RootBeanDefinition。
      //  如果BeanName是子Bean,同時會合並父類的相關屬性。
         final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
         checkMergedBeanDefinition(mbd, beanName, args);

         //先實例化依賴的所有的bean
         String[] dependsOn = mbd.getDependsOn();
         if (dependsOn != null) {
            for (String dependsOnBean : dependsOn) {
               if (isDependent(beanName, dependsOnBean)) {
                  throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Circular depends-on relationship between '" + beanName + "' and '" + dependsOnBean + "'");
               }
               // 緩存依賴調用
               registerDependentBean(dependsOnBean, beanName);
               getBean(dependsOnBean);
            }
         }

         // 實例化所依賴的bean之後就可以實例化mbd本身了。
         //	單例模式創建
         if (mbd.isSingleton()) {
            sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
               @Override
               public Object getObject() throws BeansException {
                  try {
                  // 創建bean
                     return createBean(beanName, mbd, args);
                  }
                  catch (BeansException ex) {
                     // Explicitly remove instance from singleton cache: It might have been put there
                     // eagerly by the creation process, to allow for circular reference resolution.
                     // Also remove any beans that received a temporary reference to the bean.
                     destroySingleton(beanName);
                     throw ex;
                  }
               }
            });
            // 這裏等同於上面的方法,解決FactoryBean等問題。
            bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
         }

         else if (mbd.isPrototype()) {
            // It's a prototype -> create a new instance.
            Object prototypeInstance = null;
            try {
               beforePrototypeCreation(beanName);
               prototypeInstance = createBean(beanName, mbd, args);
            }
            finally {
               afterPrototypeCreation(beanName);
            }
            bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
         }
					// 如果不是singleton和prototype類型的bean,則需要使用自己指定的scope的委託類來實現初始化。
         else {
            String scopeName = mbd.getScope();
            final Scope scope = this.scopes.get(scopeName);
            if (scope == null) {
               throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
            }
            try {
               Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
                  @Override
                  public Object getObject() throws BeansException {
                     beforePrototypeCreation(beanName);
                     try {
                        return createBean(beanName, mbd, args);
                     }
                     finally {
                        afterPrototypeCreation(beanName);
                     }
                  }
               });
               bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
            }
            catch (IllegalStateException ex) {
               throw new BeanCreationException(beanName,
                     "Scope '" + scopeName + "' is not active for the current thread; consider " +
                     "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
                     ex);
            }
         }
      }
      catch (BeansException ex) {
         cleanupAfterBeanCreationFailure(beanName);
         throw ex;
      }
   }

   // Check if required type matches the type of the actual bean instance.
   if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
      try {
         return getTypeConverter().convertIfNecessary(bean, requiredType);
      }
      catch (TypeMismatchException ex) {
         if (logger.isDebugEnabled()) {
            logger.debug("Failed to convert bean '" + name + "' to required type [" +
                  ClassUtils.getQualifiedName(requiredType) + "]", ex);
         }
         throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
      }
   }
   return (T) bean;
}
  • FactoryBean#getObject()代理了getBean()方法。

  • getSingleton() 這一步是嘗試從緩存中獲取單例bean

  • protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // singletonObjects concurrentHashMap 存儲了BeanName和bean實例之間的關係。
       Object singletonObject = this.singletonObjects.get(beanName);
       if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
          synchronized (this.singletonObjects) {
          // 判斷一下是否正在加載,正在加載則不處理。
          // earlySingletonObjects也是保存beanName和bean實例之間的關係,但不同的是bean被放入之後
          // 即使bean還在創建過程中,就可以通過getBean方法獲取了,目的是爲了檢測循環引用。
             singletonObject = this.earlySingletonObjects.get(beanName);
             if (singletonObject == null && allowEarlyReference) {
             // singletonFactories 用來保存beanName和創建bean工廠之間的關係。
             // ObjectFactory只是一個普通的工廠接口,不同於FactoryBean。
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                   singletonObject = singletonFactory.getObject();
                   this.earlySingletonObjects.put(beanName, singletonObject);
                   this.singletonFactories.remove(beanName);
                }
             }
          }
       }
       return (singletonObject != NULL_OBJECT ? singletonObject : null);
    }
    
  • getObjectForBeanInstance

    看完這個方法之後,我們來分析getObjectForBeanInstance;

    protected Object getObjectForBeanInstance(
          Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
    
       // 不屬於FactoryBean或者beanName有&前綴  異常
       if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
          throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
       }
    
      //現在我們有了bean實例,它可能是一個普通的bean或FactoryBean。
    	//如果它是FactoryBean,我們將使用它來創建Bean實例,
    	//除非調用者實際上想要對工廠的引用。 
       if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
          return beanInstance;
       }
    
       Object object = null;
       if (mbd == null) {
       // 嘗試從緩存中加載bean
          object = getCachedObjectForFactoryBean(beanName);
       }
       if (object == null) {
          // Return bean instance from factory.
     		 //  可以確定Object是FactoryBean,從FactoryBean中獲取對象
          FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
          // Caches object obtained from FactoryBean if it is a singleton.
          if (mbd == null && containsBeanDefinition(beanName)) {
          // 將存儲XML配置文件的GernericBeanDefinition轉換爲RootBeanDefinition
          // 如果指定BeanName是子Bean的話同時會合並父類的相關屬性。
             mbd = getMergedLocalBeanDefinition(beanName);
          }
          // 是否是用戶定義的bean而不是應用程序本身定義的bean
          boolean synthetic = (mbd != null && mbd.isSynthetic());
          object = getObjectFromFactoryBean(factory, beanName, !synthetic);
       }
       return object;
    }
    

我們可以看到真正的獲取對象方法在getObjectFromFactoryBean中,限於篇幅,我們就不點進去了,但這個方法中主要的代碼就是從FactoryBean#getObject()及一些前置後置處理。回到doGetBean當中,我們發現沒有實例化的單例對象會調用createBean方法。我們找到一個實現類AbstractAutowireCapableBeanFactory的createBean方法。

  • createBean
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
   if (logger.isDebugEnabled()) {
      logger.debug("Creating instance of bean '" + beanName + "'");
   }
   RootBeanDefinition mbdToUse = mbd;

   //確保Class被加載
   Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
   if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
      mbdToUse = new RootBeanDefinition(mbd);
      mbdToUse.setBeanClass(resolvedClass);
   }

   // Prepare method overrides.
   try {
   //。處理<lookup-method>和<replaced-method>標籤的方法
      mbdToUse.prepareMethodOverrides();
   }
   catch (BeanDefinitionValidationException ex) {
      throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
            beanName, "Validation of method overrides failed", ex);
   }

   try {
      // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
      // 添加BeanPostProcessor的代理
      Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
      if (bean != null) {
         return bean;
      }
   }
   catch (Throwable ex) {
      throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
            "BeanPostProcessor before instantiation of bean failed", ex);
   }
	// 將持有代理的mbdToUse傳入進行bean對象的創建
   Object beanInstance = doCreateBean(beanName, mbdToUse, args);
   if (logger.isDebugEnabled()) {
      logger.debug("Finished creating instance of bean '" + beanName + "'");
   }
   return beanInstance;
}
  • doCreateBean

    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
       // Instantiate the bean.
       BeanWrapper instanceWrapper = null;
       if (mbd.isSingleton()) {
          instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
       }
       if (instanceWrapper == null) {
       //instanceWrapper爲null代表不是FactoryBean,則實例化bean
          instanceWrapper = createBeanInstance(beanName, mbd, args);
       }
       final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
       Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
    
       // Allow post-processors to modify the merged bean definition.
       synchronized (mbd.postProcessingLock) {
          if (!mbd.postProcessed) {
             applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
             mbd.postProcessed = true;
          }
       } 
       //  是否需要提前曝光。
       boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
             isSingletonCurrentlyInCreation(beanName));
       if (earlySingletonExposure) {
          if (logger.isDebugEnabled()) {
             logger.debug("Eagerly caching bean '" + beanName +
                   "' to allow for resolving potential circular references");
          }
          //。爲了避免後期循環依賴,可以在bean初始化完成前,將創建實例的ObjectFactory加入工廠。
          addSingletonFactory(beanName, new ObjectFactory<Object>() {
             @Override
             public Object getObject() throws BeansException {
                return getEarlyBeanReference(beanName, mbd, bean);
             }
          });
       }
    
       // Initialize the bean instance.
       Object exposedObject = bean;
       try {
       // 對bean進行填充,將各個屬性賦值。如果有循環依賴則遞歸初始化依賴bean。
          populateBean(beanName, mbd, instanceWrapper);
          if (exposedObject != null) {
          // 調用初始化方法,init-method方法。以及BeanPostProcessor的回調
             exposedObject = initializeBean(beanName, exposedObject, mbd);
          }
       }
       catch (Throwable ex) {
          if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
             throw (BeanCreationException) ex;
          }
          else {
             throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
          }
       }
    
       if (earlySingletonExposure) {
          Object earlySingletonReference = getSingleton(beanName, false);
          if (earlySingletonReference != null) {
             if (exposedObject == bean) {
                exposedObject = earlySingletonReference;
             }
             else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
                String[] dependentBeans = getDependentBeans(beanName);
                Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
                for (String dependentBean : dependentBeans) {
                   if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
                      actualDependentBeans.add(dependentBean);
                   }
                }
                if (!actualDependentBeans.isEmpty()) {
                   throw new BeanCurrentlyInCreationException(beanName,
                         "Bean with name '" + beanName + "' has been injected into other beans [" +
                         StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
                         "] in its raw version as part of a circular reference, but has eventually been " +
                         "wrapped. This means that said other beans do not use the final version of the " +
                         "bean. This is often the result of over-eager type matching - consider using " +
                         "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
                }
             }
          }
       }
    
       // Register bean as disposable.
       try {
          registerDisposableBeanIfNecessary(beanName, bean, mbd);
       }
       catch (BeanDefinitionValidationException ex) {
          throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
       }
    
       return exposedObject;
    }
    

    這個方法中比較重要的三步

    • createBeanInstance 實例化bean,將BeanDefinition轉化爲BeanWrapper。
    • populateBean 屬性賦值
    • initializeBean 毀掉方法
createBeanInstance
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
   // 解析class
   Class<?> beanClass = resolveBeanClass(mbd, beanName);

   if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
      throw new BeanCreationException(mbd.getResourceDescription(), beanName,
            "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
   }
	// 如果工廠方法部位空則使用工廠方法初始化策略
   if (mbd.getFactoryMethodName() != null)  {
      return instantiateUsingFactoryMethod(beanName, mbd, args);
   }

   // Shortcut when re-creating the same bean...
   boolean resolved = false;
   boolean autowireNecessary = false;
   if (args == null) {
      synchronized (mbd.constructorArgumentLock) {
         if (mbd.resolvedConstructorOrFactoryMethod != null) {
            resolved = true;
            autowireNecessary = mbd.constructorArgumentsResolved;
         }
      }
   }
   if (resolved) {
      if (autowireNecessary) {
      // 處理構造函數依賴注入
         return autowireConstructor(beanName, mbd, null, null);
      }
      else {
      // 無參構造函數
         return instantiateBean(beanName, mbd);
      }
   }

// 判斷是否採用有參構造函數
   // Need to determine the constructor...
   Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
   if (ctors != null ||
         mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
         mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
      return autowireConstructor(beanName, mbd, ctors, args);
   }

   //調用無參構造函數
   return instantiateBean(beanName, mbd);
}
  • 無參構造函數instantiateBean -> getInstantitionStrategy().instantiate()

  • 下面我們看一下實例化策略

    public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
       // Don't override the class with CGLIB if no overrides.
       // 如果不存在方法覆載,則直接使用反射生成對象
       if (bd.getMethodOverrides().isEmpty()) {
          Constructor<?> constructorToUse;
          synchronized (bd.constructorArgumentLock) {
             constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
             if (constructorToUse == null) {
                final Class<?> clazz = bd.getBeanClass();
                if (clazz.isInterface()) {
                   throw new BeanInstantiationException(clazz, "Specified class is an interface");
                }
                try {
                   if (System.getSecurityManager() != null) {
                      constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor<?>>() {
                         @Override
                         public Constructor<?> run() throws Exception {
                            return clazz.getDeclaredConstructor((Class[]) null);
                         }
                      });
                   }
                   else {
                      constructorToUse = clazz.getDeclaredConstructor((Class[]) null);
                   }
                   bd.resolvedConstructorOrFactoryMethod = constructorToUse;
                }
                catch (Exception ex) {
                   throw new BeanInstantiationException(clazz, "No default constructor found", ex);
                }
             }
          }
          return BeanUtils.instantiateClass(constructorToUse);
       }
       else {
          //存在方法覆寫,則需要使用cglib
          return instantiateWithMethodInjection(bd, beanName, owner);
       }
    }
    
  • populateBean

    protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
       PropertyValues pvs = mbd.getPropertyValues();
    
       if (bw == null) {
          if (!pvs.isEmpty()) {
             throw new BeanCreationException(
                   mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
          }
          else {
             // Skip property population phase for null instance.
             return;
          }
       }
    
     	// bean的實例化已經完成,但是還未給屬性複製
     	// InstantiationAwareBeanPostProcessor可以對bean進行狀態的修改
       boolean continueWithPropertyPopulation = true;
    
       if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
          for (BeanPostProcessor bp : getBeanPostProcessors()) {
             if (bp instanceof InstantiationAwareBeanPostProcessor) {
                InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                   continueWithPropertyPopulation = false;
                   break;
                }
             }
          }
       }
    
       if (!continueWithPropertyPopulation) {
          return;
       }
    
       if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
             mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
          MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
    
    
          // 根據名稱注入屬性
          // newPvs中存儲了一個propertyValueList,
          // list裏面裝有屬性PropertyValue,含有屬性的名稱和值等屬性
          if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
             autowireByName(beanName, mbd, bw, newPvs);
          }
    
          // 根據類型注入屬性
          if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
             autowireByType(beanName, mbd, bw, newPvs);
          }
    
          pvs = newPvs;
       }
    
       boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
       boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
    
       if (hasInstAwareBpps || needsDepCheck) {
          PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
          if (hasInstAwareBpps) {
             for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof InstantiationAwareBeanPostProcessor) {
                   InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                   pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                   if (pvs == null) {
                      return;
                   }
                }
             }
          }
          if (needsDepCheck) {
             checkDependencies(beanName, mbd, filteredPds, pvs);
          }
       }
    	// 將屬性應用到bean中
       applyPropertyValues(beanName, mbd, bw, pvs);
    }
    
    • InstantiationAwareBeanPostProcessor接口繼承BeanPostProcessor接口,它內部提供了3個方法,再加上BeanPostProcessor接口內部的2個方法,所以實現這個接口需要實現5個方法。

      // postProcessBeforeInstantiation方法的作用在目標對象被實例化之前調用的方法,可以返回目標實例的一個代理用來代替目標實例
      // beanClass參數表示目標對象的類型,beanName是目標實例在Spring容器中的name
      // 返回值類型是Object,如果返回的是非null對象,接下來除了postProcessAfterInitialization方法會被執行以外,其它bean構造的那些方法都不再執行。否則那些過程以及postProcessAfterInitialization方法都會執行
      Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException;

      // postProcessAfterInstantiation方法的作用在目標對象被實例化之後並且在屬性值被populate之前調用
      // bean參數是目標實例(這個時候目標對象已經被實例化但是該實例的屬性還沒有被設置),beanName是目標實例在Spring容器中的name
      // 返回值是boolean類型,如果返回true,目標實例內部的返回值會被populate,否則populate這個過程會被忽視
      boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException;

      // postProcessPropertyValues方法的作用在屬性中被設置到目標實例之前調用,可以修改屬性的設置
      // pvs參數表示參數屬性值(從BeanDefinition中獲取),pds代表參數的描述信息(比如參數名,類型等描述信息),bean參數是目標實例,beanName是目標實例在Spring容器中的name
      // 返回值是PropertyValues,可以使用一個全新的PropertyValues代替原先的PropertyValues用來覆蓋屬性設置或者直接在參數pvs上修改。如果返回值是null,那麼會忽略屬性設置這個過程(所有屬性不論使用什麼註解,最後都是null)
      PropertyValues postProcessPropertyValues(
      PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)
      throws BeansException;

      InstantiationAwareBeanPostProcessor接口的主要作用在於目標對象的實例化過程中需要處理的事情,包括實例化對象的前後過程以及實例的屬性設置
      postProcessBeforeInstantiation方法是最先執行的方法,它在目標對象實例化之前調用,該方法的返回值類型是Object,我們可以返回任何類型的值。由於這個時候目標對象還未實例化,所以這個返回值可以用來代替原本該生成的目標對象的實例(比如代理對象)。如果該方法的返回值代替原本該生成的目標對象,後續只有postProcessAfterInitialization方法會調用,其它方法不再調用;否則按照正常的流程走
      postProcessAfterInstantiation方法在目標對象實例化之後調用,這個時候對象已經被實例化,但是該實例的屬性還未被設置,都是null。如果該方法返回false,會忽略屬性值的設置;如果返回true,會按照正常流程設置屬性值
      postProcessPropertyValues方法對屬性值進行修改(這個時候屬性值還未被設置,但是我們可以修改原本該設置進去的屬性值)。如果postProcessAfterInstantiation方法返回false,該方法不會被調用。可以在該方法內對屬性值進行修改
      父接口BeanPostProcessor的2個方法postProcessBeforeInitialization和postProcessAfterInitialization都是在目標對象被實例化之後,並且屬性也被設置之後調用的
      Instantiation表示實例化,Initialization表示初始化。實例化的意思在對象還未生成,初始化的意思在對象已經生成

到這一步實例化和屬性賦值都已經完成了,接下來就進行初始化操作

initializeBean
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
   if (System.getSecurityManager() != null) {
      AccessController.doPrivileged(new PrivilegedAction<Object>() {
         @Override
         public Object run() {
            invokeAwareMethods(beanName, bean);
            return null;
         }
      }, getAccessControlContext());
   }
   else {
   // 如果bean實現了一些Aware接口,則進行回調。
   // 實現Aware接口的bean會被注入相應實例。
   // 例如我們項目開發過程中常用的ApplicationContextAware接口來獲取ApplicationContext
      invokeAwareMethods(beanName, bean);
   }

   Object wrappedBean = bean;
   if (mbd == null || !mbd.isSynthetic()) {
   //  BeanPostProcessor的postProcessBeforeInitialization回調
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
   }

   try {
   // 調用用戶自定義的init方法
      invokeInitMethods(beanName, wrappedBean, mbd);
   }
   catch (Throwable ex) {
      throw new BeanCreationException(
            (mbd != null ? mbd.getResourceDescription() : null),
            beanName, "Invocation of init method failed", ex);
   }

   if (mbd == null || !mbd.isSynthetic()) {
   // BeanPostProcessor的postProcessAfterInitialization回調
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
   }
   return wrappedBean;
}

走到這一步,我們就知道了BeanPostProcessor接口到底在哪裏進行回調了。實例化及屬性賦值完成之後對初始化的對象進行前後回調了。

總結

限於篇幅,有些地方的代碼可能還不夠深入,但SpringIOC容器初始化的過程就大致如上所示了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章