spring步步前行(IOC)-Spring beanFactory詳解(一)

spring步步前行(IOC)-Spring beanFactory詳解(一)

beanFactory組成

在這裏插入圖片描述

在接觸spring的ioc的時候 factory與applicationContext它們倆真真攪得糊里糊塗,下定決心重新認識下它們倆

我們以DefaultListableBeanFactory爲例:

在這裏插入圖片描述

其成員變量beanDefinitionMap從後面的分析有介紹,這就是存放我們xml定義的bean信息

其繼承了beanFactory的同時還實現一些接口

 ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable

我們關注BeanDefinitionRegistry接口,字面意思是bean定義註冊器

在這裏插入圖片描述

從其方法上我們可以看出其具備register/remove等beanDefinition操作

這就是一個BeanFactory的大概功能

由於內容繁多,我們從兩個問題出發,去了解beanfactory

  • beanFactory是怎麼初始化
  • beanFactory如何去加載xml中的bean

準備工作

  • 創建一個bean

  • public class TargetBean {
      public void hellobean() {
        System.out.println("hello bean...");
      }
    }
    
  • 聲明bean.xml 並藉助ClassPathXmlApplicationContext我們get一下我們的目標tartbean

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
    
    
        <bean id="targethello" class="org.tutor.spring.ioc.TargetBean"></bean>
    
    </beans>
    
  • ApplicationContext context = new ClassPathXmlApplicationContext('bean.xml');
    TargetBean bean = context.getBean("targethello");
    bean.hellobean();
    
  • 運行結果很明顯我們看到了控制檯打印的“hello bean…"的結果,這時我們暫時將bean.xml拿掉我們看看它的報錯信息,如下:

    在這裏插入圖片描述

    這裏的打印向我們透露的幾個關鍵類AbstractApplicationContext AbstractXmlApplicationContext AbstractBeanDefinitionReader

beanFactory是初始化

我們debug調試運行看看beanFactory如何初始化的:

  • 首先ClassPathXmlApplicationContext內將我們傳入的configLocation(即bean.xml)用String[]包裝了一下

    在這裏插入圖片描述

  • 接着在構造內進行setConfigLocations操作

    在這裏插入圖片描述

    該方法在AbstractRefreshableConfigApplicationContext中實現,對該類中的configLocations進行賦值,如下

    在這裏插入圖片描述

    可能有人對resolvePath想深入瞭解,其實該操作就是對我們傳入的location中的佔位符進行處理,有興趣的童鞋,可以自行深入瞭解一下

  • setConfigLocations之後就是ClassPathXmlApplicationContext的refresh操作,該refresh方法實現在AbstractApplicationContext中,如下:

    在這裏插入圖片描述

    這裏也就是初始化SpringBeanFactory的核心部分了

    • 我們先看obtainFreshBeanFactory()如何獲取一個BeanFactory

      在這裏插入圖片描述

      在這裏插入圖片描述

      ​ 首先refreshBeanFactory中,若存在Factory即容器,先銷燬內裏的bean,spring保證只有一個容器,然後在線程安全下,爲beanFactory賦值

    • createBeanFactory()內部爲我們new了一個DefaultListableBeanFactory,然後爲這個DefaultListableBeanFactory設置序列化id,最後定製化beanFactory

      在這裏插入圖片描述

      對於定製化而言,其實就是爲一些解析器Resolver設置BeanFactory,以及對beanFactory的一些功能進行設置,好比是否可以循環引用,允許bean定義覆蓋等

      在這裏插入圖片描述

    • 最後也就到了最關鍵的地方loadBeanDefinitions(beanFactory),我們先看看loadBeanDefinitions,如下:

      在這裏插入圖片描述

加載bean

  • loadBeanDefinitions

    從上面loadBeanDefinitions方法中,我們可以看到其創建了一個XmlBeanDefinitionReader,並將之前準備好的beanFactory傳入,我們看看XmlBeanDefinitionReader構造:

    在這裏插入圖片描述

    這裏的Registry就是我們的beanFactory了,我們在篇幅最初說的beanFactory實現了BeanDefinitionRegistry的接口,也就具備了註冊beanDefinition等功能。

    看其構造我們發現其將registry傳入父類處理了,我們在看看其將registry如何處理

    在這裏插入圖片描述

    由於我們傳入的是beanFactory所以這裏都是默認配置,即PathMatchingResourcePatternResolver和StandardEnvironment

    接着外部重新setEnvironment和setResourceLoader以及setEntityResolver,即StandardEnvironment和ClassPathXmlApplicationContext以及ResourceEntityResolver解析器

    最後進行初始化BeanDefinitionReader

  • 加載

    有了之前創建的xmlBeanDefinition,緊接着我們通過AbstractXmlApplicationContext內部實現的loadBeanDefinitions開始加載bean

    在這裏插入圖片描述

    getConfigLocations就是我們最開始ClassPathXmlApplicationContext幫我們包裝的那個bean.xml

    • xmlBeanDefinitionReader.loadBeanDEfinitions根據我們的bean.xml去加載我們的bean,經過一系列加載,最終進入XmlBeanDefinitionReader的doLoadBeanDefinitions進行registerBeanDefinitions操作

    • registerBeanDefinitions想容器中註冊我們的bean

      在這裏插入圖片描述

      這時DefaultBeanDefinitionDocumentReader的regitsterBeandefinition進行xml解析進行bean處理

      在這裏插入圖片描述

      循環每一個元素,分別解析

      在這裏插入圖片描述

      經過xml解析

      在這裏插入圖片描述

    • 藉助BeanDefinitionReaderUtils.registerBeanDefinition 完整bean的註冊

      在這裏插入圖片描述

      通過我們beanfactory進行registerBeanDefinition,由於beanfactory內的registerbeanDefinition方法較長,在這僅羅列主要部分

      在這裏插入圖片描述

      由此我們可以看出beanFactory維護的beanDefinitionMap存放了我們加載的bean信息

      在這裏插入圖片描述

      即key爲我們bean.xml中爲bean設置的id,value是bean信息

      • 注意BeanDefinitionReaderUtils.registerBeanDefinition中,如果有別名也會進行別名註冊,此處不再進行詳細分析,有興趣的同學,可自行深入瞭解

由此我們以上初始化及加載兩個問題,解析至此

這裏只講述了refresh中的obtainBeanFactory以前的部分,refresh這塊我會再單獨寫一篇詳細關於這個refresh核心方法的分析

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