spring源碼系列(十): 讀取xml入口類 ClassPathXmlApplicationContext 分析


環境准備:

使用spring5.1.6版本

 

1 xml配置文件

<?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.xsd">


    <bean id="user" class="com.hou.spring.bean.User"></bean>
</beans>

2 測試類

public class BeanTest{

    @Test
    public void beanTest(){
        //spring4之后XmlBeanFactory被廢棄,改用以下方式
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-bean.xml");
        User user = (User) applicationContext.getBean("user");
        System.out.println(user);
    }
}

然后點進去源碼,跟着一步步debug來分析:

1 構造器調用:

ClassPathXmlApplicationContext的構造器中調用類同名方法:

 

 點擊this跳轉到初始化方法:

2 super()方法是一直到父類AbstractApplicationContext中,將ApplicationContext的環境屬性設置給本類的環境屬性,包括一些profile,系統屬性等

3 setConfigLocations方法也是調用父類方法,將xml配置文件名字設置給父類的String數組屬性

 

4 refresh() 方法,所有的邏輯其實都在這個方法里面進行,主要分析這個方法:

5 prepareRefresh主要還是環境屬性的一些初始化,主要看第二步:

// Tell the subclass to refresh the internal bean factory. 告訴子類刷新內部bean工廠
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

點進去obtainFreshBeanFactory:

6 首先看refreshBeanFactory方法,注意,如果不知道是哪個子類的話,可以跟着debug斷點走:

主要分為這么幾個步驟:

一 首先判斷本類的DefaultListableBeanFactory屬性是否為null,如果不為null,就先清除一寫跟Bean有關的Map或者List等屬性集合

二 將BeanFactory設置為null,序列化id設置為null,
三 創建DefaultListableBeanFactory,這個類很重要,是springBean初始化的核心類,
四 對beanFactory進行設置,bean注冊等操作,最后將beanFactory賦值給本類的beanFactory屬性

 7 customizeBeanFactory(beanFactory); 只做了兩件事:

8 loadBeanDefinitions:   Bean的注冊主要是在這一步進行,下面進行分析,這個方法有5個子類實現:

我寫的測試類不是Web項目,所以會進入AbstractXmlApplicationContext這個類里的方法,如果是Web項目,會走XmlWebApplicationContext:

 首先創建XmlBeanDefinitionReader:xml配置讀寫器然后設置環境屬性以及資源加載器為ClassPathXmlApplicationContext,這個加載器很重要,后面會用到

接着初始化讀取器: initBeanDefinitionReader,最后加載Bean

8 initBeanDefinitionReader

這個方法默認實現是空的,允許用戶自定義實現讀取器的定制化,需要實現接口,可以設置xml解析完成校驗,定制化解析器等

9 loadBeanDefinitions: 加載Bean信息,點進去:

這個方法主要是加載類的兩個資源屬性,Resource[] 和xml位置信息,主要看加載Xml的:

10 reader.loadBeanDefinitions(configLocations);

循環加載xml文件的Bean返回Bean總個數,查看加載方法:

11 查看這個load方法:

這里需要注意第八步設置的加載器,查看加載器的時序圖:

 

因為有繼承關系所以直接進if分支,繼續分析if分支代碼:

主要步驟:

1 獲取加載器中的Resource[] 數組

2 加載資源中的Bean,返回加載數量

12 查看loadBeanDefinitions,循環加載了所有的資源,返回總數

13 查看單個加載方法loadBeanDefinitions,主要看中間一段邏輯:

這里對正在解析的xml資源放入ThreadLocal中,保證只有本次線程可以訪問,加載完之后再移除

13 查看doLoadBeanDefinitions(inputSource, encodedResource.getResource());

 

 

 

 
       


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM