深入理解-Spring-之源碼剖析IOC(一)

作者:莫那魯道

鏈接:http://thinkinjava.cn

引言

作爲Java程序員,Spirng我們再熟悉不過,可以說比自己的女朋友還要親密,每天都會和他在一起,然而我們真的瞭解spring嗎?

我們都知道,Spring的核心是IOC和AOP,但樓主認爲,如果從這兩個核心中挑選一個更重要的,那非IOC莫屬。AOP也是依賴於IOC,從某些角度講,AOP就是IOC的一個擴展功能。

什麼是IOC? IOC解決了什麼問題?IOC的原理是什麼?Spring的IOC是怎麼實現的?今天我們將會將這幾個問題一起解決。

1. 什麼是IOC?

控制反轉(Inversion of Control,縮寫爲IoC),是面向對象編程中的一種設計原則,可以用來減低計算機代碼之間的耦合度。

其中最常見的方式叫做依賴注入(Dependency Injection,簡稱DI),還有一種方式叫“依賴查找”(Dependency Lookup)。

通過控制反轉,對象在被創建的時候,由一個調控系統內所有對象的外界實體,將其所依賴的對象的引用傳遞給它。也可以說,依賴被注入到對象中。

這是維基百科的說法,樓主按照自己的思路分析一下IOC,樓主認爲,分析一個問題,或者說證明一個事情,有2種方法,一是正向驗證,即按照該事物的邏輯去驗證正確性,還有一種是反向驗證,證明該事物是否正確。

樓主想反向證明IOC,我們提出一個疑問:如果沒有IOC會怎麼樣?

想象一下,在沒有IOC的世界裏,我們的系統會有大量的對象,這些對象有些是數據,有些是處理數據的。

並且各個對象相互依賴,我們需要控制他們的依賴關係,什麼時候new ,什麼時候銷燬,什麼時候需要單例,什麼時候不需要單例等等這些問題。

你能想象嗎?當你一個系統有幾千個類,你如何管理他們的依賴關係,說起依賴,我們可能會想起 maven 或者 gradle,他們管理着我們的 jar 包依賴,而我們的系統代碼呢?

但是如果有一種東西,他能夠幫助我們管理所有類的創建,銷燬,是否是單例模式,類與類之間的多層依賴關係(在我們的MVC框架中,3層依賴已經是最少),那該多好,我們只需要關注業務邏輯。於是 ,IOC誕生了。

2. IOC 解決了什麼問題?

簡單來說, IOC 解決了類與類之間的依賴關係。程序員將控制類與類之間依賴的權利交給了IOC,即:控制被反轉了。

3. IOC 的原理是什麼?

其實 IOC 的原理很簡單,底層就是java的反射。給定一個字符串能創建一個實例,利用set方法對實例的依賴進行注入。

我們來一段代碼證明一下是多麼的簡單:

可以看到該代碼非常的簡單,但實際上IOC 就是這麼簡單,在真正的開發中,我們只需要在配置文件給定一個類名字符串,就什麼都不用管了,對象就會創建出來,系統啓動完畢之後,我們只需要直接使用該對象就好了,不必自己去new。

解決了我們的對象創建問題。我們通過反射調用該方法的setText方法,完成了依賴注入。我們不再需要去new,然後去set,IOC 已經爲我們做好了一切。

介紹完了幾個基本知識,其實都是爲我們今天的重頭戲做準備,Spring的IOC是怎麼實現的?

4. Spring的IOC是怎麼實現的?

這是一個浩大的問題,雖然底層實現可能就那麼幾行代碼,但樓主說過,所有框架的底層技術都很簡單,但是我們的框架大師們爲了軟件的健壯性,擴展性和性能,做了無數的優化,我們的系統源碼也就變得越來越復。

spirng的 release 版本至今已經到了 5.0.3,和最初的 interface21 已經有了翻天覆地的變化,現在也有了springboot, springcloud,儼然一個龐大的spring家族,想分析源碼的我們該從哪裏下手呢?

萬劍歸宗,始於一處。

Bean。

我們要研究spring的IOC,我們要了解的就是spring的bean,這是spring的核心的核心。雖然bena依賴着context 模塊提供bean的環境,依賴core 提供着一系列強化的工具。

但今天我們不關心,我們只關係bean。只關心IOC。就像這個信息過載,技術不斷更新的時代,程序們需要有自己的判斷,自己需要研究什麼,什麼是最重要的?扯遠了。

在開始研究源碼之前,樓主有必要介紹一下IOC的一些核心組件,否則一旦進入源碼,就會被細節捆住,無法從宏觀的角度理解IOC。

  1. BeanFactory:這是IOC容器的接口定義,如果將IOC容器定位爲一個水桶,那麼BeanFactory 就定義了水桶的基本功能,能裝水,有把手。這是最基本的,他的實現類可以拓展水桶的功能。
  2. ApplicationContext:這是我們最常見的,上面我們說水桶,BeanFactory是最基本的水桶,而 ApplicationContext 則是擴展後的水桶,它通過繼承 MessageSource,ResourceLoader,ApplicationEventPublisher 接口,在BeanFactory 簡單IOC容器的基礎上添加了許多對高級容器的支持。
  3. BeanDefinition:我們知道,每個bean都有自己的信息,各個屬性,類名,類型,是否單例,這些都是bena的信息,spring中如何管理bean的信息呢?對,就是 BeanDefinition, Spring通過定義 BeanDefinition 來管理基於Spring的應用中的各種對象以及他們直接的相互依賴關係。BeanDefinition 抽象了我們對 Bean的定義,是讓容器起作用的主要數據類型。對 IOC 容器來說,BeanDefinition 就是對依賴反轉模式中管理的對象依賴關係的數據抽象,也是容器實現依賴反轉功能的核心數據結構

4.1. 搭建源碼研究環境

樓主研究源碼的思路有2個,一個是創建一個簡單的spirng maven 項目,還有一個是直接從 spirng 的github 上 clone 源碼。

這是樓主的普通 maven 項目:

這是樓主的 clone 的 spring-framework 源碼:

注意:clone 該源碼的時候,樓主很艱辛,因爲要科學上網,否則 gradle 無法下載依賴會導致報錯。如果各位無法科學上網,可以使用 maven 項目勉強學習。

4.2. 開啓研究源碼第一步

我們打開spring-framework 源碼。

還記的我們初學spring的寫的第一行代碼是什麼嗎?

怎麼寫配置文件樓主就不說了,我們回憶一下我們最初學spring的時候,雖然現在都是2017年了,我們都用springboot,都是用註解了,但spring的核心代碼還是 spring 之父 Rod Johnson 在 2001 年寫的。所以不影響我們學習spring 的核心。

我們仔細看看該代碼(該代碼位置必須在spring-context模塊下):

package test;import org.springframework.beans.tests.Person;import org.springframework.context.ApplicationContext;import org.springframework.context.support.FileSystemXmlApplicationContext;public class Test {
 public static void main(String[] args) throws ClassNotFoundException {

   ApplicationContext ctx = new FileSystemXmlApplicationContext
       ("spring-beans/src/test/resources/beans.xml");
   System.out.println("number : " + ctx.getBeanDefinitionCount());
   ((Person) ctx.getBean("person")).work();
 }
}

熟悉的 ApplicatContext ,看名字是應用上下文,什麼意思呢?就是spirng整個運行環境的背景,好比一場舞臺劇,ApplicatContext 就是舞臺,IOC 管理的Bean 就是演員,Core 就是道具。而ApplicatContext 的標準實現是 FileSystemXmlApplicationContext。

該類的構造方法中包含了容器的啓動,IOC的初始化。所以我們 debug 啓動該項目,運行main方法。打好斷點。

4.3. 從 FileSystemXmlApplicationContext 開始剖析

從這裏開始,我們即將進入複雜的源碼。

我們進入 FileSystemXmlApplicationContext 的構造方法:

可以看到該構造方法被重載了,可以傳遞 configLocation 數組,也就是說,可以傳遞過個配置文件的地址。默認刷新爲true,parent 容器爲null。進入另一個構造器:

該構造器做了2件事情,一是設置配置文件,二是刷新容器,我們可以感覺到,refresh 方法纔是初始化容器的重要方法。我們進入該方法看看:該方法是 FileSystemXmlApplicationContext 的父類 AbstractApplicationContext 的方法。

4.4. AbstractApplicationContext.refresh() 方法實現

/**
  *
  * 1. 構建Be按Factory,以便產生所需要的bean定義實例
  * 2. 註冊可能感興趣的事件
  * 3. 創建bean 實例對象
  * 4. 觸發被監聽的事件
  *
  */
 @Override
 public void refresh() throws BeansException, IllegalStateException {
   synchronized (this.startupShutdownMonitor) {
     // 爲刷新準備應用上下文
     prepareRefresh();
     // 告訴子類刷新內部bean工廠,即在子類中啓動refreshBeanFactory()的地方----創建bean工廠,根據配置文件生成bean定義
     ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
     // 在這個上下文中使用bean工廠
     prepareBeanFactory(beanFactory);

     try {
       // 設置BeanFactory的後置處理器
       postProcessBeanFactory(beanFactory);
       // 調用BeanFactory的後處理器,這些後處理器是在Bean定義中向容器註冊的
       invokeBeanFactoryPostProcessors(beanFactory);
       // 註冊Bean的後處理器,在Bean創建過程中調用
       registerBeanPostProcessors(beanFactory);
       //對上下文的消息源進行初始化
       initMessageSource();
       // 初始化上下文中的事件機制
       initApplicationEventMulticaster();
       // 初始化其他的特殊Bean
       onRefresh();
       // 檢查監聽Bean並且將這些Bean向容器註冊
       registerListeners();
       // 實例化所有的(non-lazy-init)單件
       finishBeanFactoryInitialization(beanFactory);
       //  發佈容器事件,結束refresh過程
       finishRefresh();
     }

     catch (BeansException ex) {
       if (logger.isWarnEnabled()) {
         logger.warn("Exception encountered during context initialization - " +
             "cancelling refresh attempt: " + ex);
       }
       // 爲防止bean資源佔用,在異常處理中,銷燬已經在前面過程中生成的單件bean
       destroyBeans();
       // 重置“active”標誌
       cancelRefresh(ex);
       throw ex;
     }

     finally {
       // Reset common introspection caches in Spring's core, since we
       // might not ever need metadata for singleton beans anymore...
       resetCommonCaches();
     }
   }
 }

可以說該方法就是整個IOC容器初始化的所有邏輯。因此,如果讀懂了該方法的每一行代碼,就瞭解了spring的整個功能。該方法的調用層次之深可以想象一下。

我們先大致說下該方法的步驟:

  1. 構建BeanFactory,以便於產生所需的 Bean。
  2. 註冊可能感興趣的事件。
  3. 常見Bean實例對象。
  4. 觸發被監聽的事件。

我們一個個來看: 首先構建BeanFactory,在哪裏實現的呢?也就是obtainFreshBeanFactory 方法,返回了一個ConfigurableListableBeanFactory,該方法調用了 refreshBeanFactory() ,該方法是個模板方法,交給了 AbstractRefreshableApplicationContext 去實現。我們看看該方法實現:

@Override
 protected final void refreshBeanFactory() throws BeansException {
   if (hasBeanFactory()) {
     // 如果存在就銷燬
     destroyBeans();
     closeBeanFactory();
   }
   try {
     // new DefaultListableBeanFactory(getInternalParentBeanFactory())
     DefaultListableBeanFactory beanFactory = createBeanFactory();
     // 設置序列化
     beanFactory.setSerializationId(getId());
     // 定製的BeanFactory
     customizeBeanFactory(beanFactory);
     // 使用BeanFactory加載bean定義 AbstractXmlApplicationContext
     loadBeanDefinitions(beanFactory);
     synchronized (this.beanFactoryMonitor) {
       this.beanFactory = beanFactory;
     }
   }
   catch (IOException ex) {
     throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
   }
 }

可以看到BeanFactory的創建過程,首先判斷是否存在了 BeanFactory,如果有則銷燬重新創建,調用 createBeanFactory 方法,該方法中就是像註釋寫的:創建了 DefaultListableBeanFactory ,也既是說,DefaultListableBeanFactory 就是 BeanFactory的默認實現。然後我們看到一個很感興趣的方法。

就是 loadBeanDefinitions(beanFactory),看名字是加載 Definitions,這個我們很感興趣,我們之前說過, Definition 是核心之一,代表着 IOC 中的基本數據結構。該方法也是個抽象方法,默認實現是 AbstractXmlApplicationContext ,我們看看該方法實現:

@Override
 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 ,用於讀取XML中配置,設置了環境,資源加載器,最後初始化,加載。可以說,該方法將加載,解析Bean的定義,也就是把用戶定義的數據結構轉化爲 IOC容器中的特定數據結構。而我們關心的則是最後一行的 loadBeanDefinitions(beanDefinitionReader) 方法。

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
   Resource[] configResources = getConfigResources();
   if (configResources != null) {
     reader.loadBeanDefinitions(configResources);
   }
   String[] configLocations = getConfigLocations();
   if (configLocations != null) {// 加載給定的路徑文件
     reader.loadBeanDefinitions(configLocations);
   }
 }

該方法會略過第一個if塊,進入第二個if塊,進入 AbstractBeanDefinitionReader.loadBeanDefinitions(String… locations) 方法,該方法內部循環加載配置文件:

@Override
 public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
   Assert.notNull(locations, "Location array must not be null");
   int counter = 0;
   for (String location : locations) {
     counter += loadBeanDefinitions(location);
   }
   return counter;
 }

我們關心的是 for 循環中的loadBeanDefinitions(location)方法,該方法核心邏輯在 AbstractBeanDefinitionReader.loadBeanDefinitions(String location, @Nullable SetactualResources) 方法中:

public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
   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 {
       Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
       int loadCount = loadBeanDefinitions(resources);// 根據配置文件加載bean定義
       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;
   }
 }

該方法首先獲取資源加載器,然後進入 if 塊,獲取資源數組,調用 loadBeanDefinitions(resources) ,根據配置文件加載Bean定義。

進入該方法後,循環加載resource 資源數組,進入 loadBeanDefinitions(resource) 方法中,最後進入到 XmlBeanDefinitionReader.loadBeanDefinitions(EncodedResource encodedResource) 方法中,該方法主要調用 doLoadBeanDefinitions(inputSource, encodedResource.getResource()) 方法。我們有必要看看該方法實現:

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
     throws BeanDefinitionStoreException {
   try {
     Document doc = doLoadDocument(inputSource, resource);
     return registerBeanDefinitions(doc, resource);// 真正的註冊bean
   }
   catch (BeanDefinitionStoreException ex) {
     throw ex;
   }
   catch (SAXParseException ex) {
     throw new XmlBeanDefinitionStoreException(resource.getDescription(),
         "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
   }
   catch (SAXException ex) {
     throw new XmlBeanDefinitionStoreException(resource.getDescription(),
         "XML document from " + resource + " is invalid", ex);
   }
   catch (ParserConfigurationException ex) {
     throw new BeanDefinitionStoreException(resource.getDescription(),
         "Parser configuration exception parsing XML from " + resource, ex);
   }
   catch (IOException ex) {
     throw new BeanDefinitionStoreException(resource.getDescription(),
         "IOException parsing XML document from " + resource, ex);
   }
   catch (Throwable ex) {
     throw new BeanDefinitionStoreException(resource.getDescription(),
         "Unexpected exception parsing XML document from " + resource, ex);
   }
 }

可以看出該方法主要邏輯是根據輸入流加載 Document 文檔對象,然後根據得到的文檔對象註冊到容器,因此我們看看倒是是如何註冊到容器的。

該方法首先創建一個 BeanDefinitionDocumentReader, 用於讀取 BeanDefinition,該對象會調用 registerBeanDefinitions(doc, createReaderContext(resource)) 方法。

該方法最後從文檔對象獲取根元素,最後調用 DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(root) 進行註冊。

該方法最核心的邏輯就是調用 parseBeanDefinitions(root, this.delegate),我們看看該方法具體實現:

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);
   }
 }

該方法就是一個解析XML 文檔的步驟,核心是調用 parseDefaultElement(ele, delegate),我們進入該方法查看,該方法調用了 processBeanDefinition(ele, delegate) 方法進行解析。我們有必要看看該方法:

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
   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));
   }
 }

首先創建一個 BeanDefinitionHolder,該方法會調用 BeanDefinitionReaderUtils.registerBeanDefinition 方法, 最後執行容器通知事件。該靜態方法實現如下:

*/
 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);
     }
   }
 }

可以看到首先從bean的持有者那裏獲取了beanName,然後調用 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()), 將bena的名字和 BeanDefinition 註冊,我們看看最後的邏輯:

@Override
 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;

   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.");
     }
     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 {
     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<>(this.beanDefinitionNames.size() + 1);
         updatedDefinitions.addAll(this.beanDefinitionNames);
         updatedDefinitions.add(beanName);
         this.beanDefinitionNames = updatedDefinitions;
         if (this.manualSingletonNames.contains(beanName)) {
           Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
           updatedSingletons.remove(beanName);
           this.manualSingletonNames = updatedSingletons;
         }
       }
     }
     else {
       // Still in startup registration phase // 最終放進這個map 實現註冊
       this.beanDefinitionMap.put(beanName, beanDefinition);// 走這裏 // private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
       this.beanDefinitionNames.add(beanName);
       this.manualSingletonNames.remove(beanName);
     }
     this.frozenBeanDefinitionNames = null;
   }

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

該方法可以說是註冊bean的最後一步,將beanName和 beanDefinition 放進一個 ConcurrentHashMap(256) 中。

那麼這個 beanDefinition 是時候創建的呢? 就是在 DefaultBeanDefinitionDocumentReader.processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) 方法中,在這裏創建了 BeanDefinitionHolder, 而該實例中解析Bean並將Bean 保存在該對象中。

所以稱爲持有者。該實例會調用 parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) 方法,該方法用於解析XML文件並創建一個 BeanDefinitionHolder 返回,該方法會調用 parseBeanDefinitionElement(ele, beanName, containingBean) 方法, 我們看看該方法:

@Nullable
 public AbstractBeanDefinition parseBeanDefinitionElement(
     Element ele, String beanName, @Nullable BeanDefinition containingBean) {

   this.parseState.push(new BeanEntry(beanName));

   String className = null;
   if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
     className = ele.getAttribute(CLASS_ATTRIBUTE).trim();// 類全限定名稱
   }
   String parent = null;
   if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
     parent = ele.getAttribute(PARENT_ATTRIBUTE);
   }

   try {
     AbstractBeanDefinition bd = createBeanDefinition(className, parent);// 創建

     parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
     bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));

     parseMetaElements(ele, bd);
     parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
     parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

     parseConstructorArgElements(ele, bd);
     parsePropertyElements(ele, bd);
     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;
 }

我們看看該方法,可以看到,該方法從XML元素中取出 class 元素,然後拿着className調用 createBeanDefinition(className, parent) 方法,該方法核心是調用 BeanDefinitionReaderUtils.createBeanDefinition 方法,我們看看該方法:

public static AbstractBeanDefinition createBeanDefinition(
     @Nullable String parentName, @Nullable String className, @Nullable ClassLoader classLoader) throws ClassNotFoundException {

   GenericBeanDefinition bd = new GenericBeanDefinition();// 泛型的bean定義,也就是最終生成的bean定義。
   bd.setParentName(parentName);
   if (className != null) {
     if (classLoader != null) {
       bd.setBeanClass(ClassUtils.forName(className, classLoader));// 設置Class 對象
     }
     else {
       bd.setBeanClassName(className);
     }
   }
   return bd;
 }

該方法很簡單,創建一個 Definition 的持有者,然後設置該持有者的Class對象,該對象就是我們在配置文件中配置的Class對象。最後返回。

到這裏,我們一走完了第一步,創建bean工廠,生成Bean定義。但還沒有實例化該類。

由於文章不能超過5萬字,所以後面的放在下一章節講解。

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