15--IoC容器啟動過程簡析及XmlBeanFactory初始化

上篇分析了Spring對資源文件的加載過程搂根,接下來我們就要開始分析Spring的IoC容器了(基于XmlBeanFactory)沮明。

1.IoC容器啟動過程簡析

注意:以BeanFactory為基礎的IoC容器在啟動完成之后偶妖,并不會立刻實例化配置文件中的bean,首次實例化發(fā)生在我們第一次向容器索取的過程中肮之。如果IoC容器這個概念生澀難懂瘤袖、或者讓人覺得有些深奧的話衣摩,那么就理解為一個類的實例化即可,只不過這個類的實例化過程捂敌,比較復雜而已艾扮!

在上一篇也介紹了IoC容器的啟動過程為:加載資源文件、解析資源文件占婉、注冊BeanDefinition泡嘴,我們再來看一個更為詳細的流程圖(該流程圖只列舉了比較重要的步驟)。


image.png

總而言之逆济,就是將xml文件轉換為SpringIoC容器的內部表示酌予。


2. XmlBeanFactory初始化

打開我們之前復習Spring知識點的測試類,以xmlBeanFactory = new XmlBeanFactory(new ClassPathResource("v2/day01.xml"));為切入點纹腌。打開XmlBeanFactory類霎终。

public class XmlBeanFactory extends DefaultListableBeanFactory {

    // 實例化XmlBeanDefinitionReader對象
    private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);


    /**
     * 通過指定Resource對象創(chuàng)建XmlBeanFactory實例
     */
    public XmlBeanFactory(Resource resource) throws BeansException {
        this(resource, null);
    }

    /**
     * 通過指定Resource對象和父BeanFactory創(chuàng)建XmlBeanFactory實例
     */
    public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
        // 依次向上實例化父類構造器
        super(parentBeanFactory);
        // 解析xml配置文件,將其轉換為IoC容器的內部表示
        this.reader.loadBeanDefinitions(resource);
    }
}

先來分析加載bean之前的準備工作,XmlBeanFactory父類初始化和XmlBeanDefinitionReader初始化升薯。

2.1 父類初始化

通過XmlBeanFactory的繼承關系依次調用各個父類的構造方法:


flowchat
st=>start: 開始
e=>end: 結束
op1=>operation: 初始化AbstractBeanFactory
op2=>operation: 初始化AbstractAutowireCapableBeanFactory
op3=>operation: 初始化DefaultListableBeanFactory
op4=>operation: 初始化XmlBeanFactory 
st->op1->op2->op3->op4->e

該過程初始化的信息很多莱褒,我們選擇其中比較重要的幾點做下介紹。

  • 忽略指定接口的自動裝配功能
public AbstractAutowireCapableBeanFactory() {
    super();
    // 忽略指定接口的自動裝配功能
    ignoreDependencyInterface(BeanNameAware.class);
    ignoreDependencyInterface(BeanFactoryAware.class);
    ignoreDependencyInterface(BeanClassLoaderAware.class);
}

忽略指定接口的自動裝配功能:如ClassA引用了ClassB涎劈,那么當Spring在獲取ClassA的實例時广凸,如果發(fā)現ClassB還沒有被初始化,那么Spring會自動初始化ClassB蛛枚。但是如果ClassB實現了BeanNameAware接口的話谅海,則Spring不會自動初始化ClassB,這就是忽略指定接口的自動裝配蹦浦。

2.2 初始化XmlBeanDefinitionReader

將xml文件中的配置轉換為IoC內部的表示就是由XmlBeanDefinitionReader來完成的扭吁。XmlBeanDefinitionReader繼承了AbstractBeanDefinitionReader類,我們來其初始化都完成了哪些操作。

protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    this.registry = registry;

    // Determine ResourceLoader to use.
    // 1侥袜、確定ResourceLoader使用蝌诡。
    if (this.registry instanceof ResourceLoader) {
        this.resourceLoader = (ResourceLoader) this.registry;
    }
    else {
        this.resourceLoader = new PathMatchingResourcePatternResolver();
    }

    // Inherit Environment if possible
    // 2、如果環(huán)境可繼承則繼承registry的環(huán)境,否則重新創(chuàng)建環(huán)境
    if (this.registry instanceof EnvironmentCapable) {
        this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
    }
    else {
        this.environment = new StandardEnvironment();
    }
}
  • 1枫吧、確定ResourceLoader使用浦旱。該方法的核心就是確定當前使用的類加載器
public PathMatchingResourcePatternResolver() {
    this.resourceLoader = new DefaultResourceLoader();
}
public DefaultResourceLoader() {
    this.classLoader = ClassUtils.getDefaultClassLoader();
}
public static ClassLoader getDefaultClassLoader() {
    ClassLoader cl = null;
    try {
        //優(yōu)先獲取線程上下文類加載器
        cl = Thread.currentThread().getContextClassLoader();
    }
    catch (Throwable ex) {
        // Cannot access thread context ClassLoader - falling back...
    }
    if (cl == null) {
        // No thread context class loader -> use class loader of this class.
        // 獲取當前類的類加載器
        cl = ClassUtils.class.getClassLoader();
        if (cl == null) {
            // getClassLoader() returning null indicates the bootstrap ClassLoader
            try {
                //獲取SystemClassLoader
                cl = ClassLoader.getSystemClassLoader();
            }
            catch (Throwable ex) {
                // Cannot access system ClassLoader - oh well, maybe the caller can live with null...
            }
        }
    }
    return cl;
}
  • 2、如果環(huán)境可繼承則繼承registry的環(huán)境,否則重新創(chuàng)建環(huán)境
    系統環(huán)境包括了系統環(huán)境屬性(主機變量信息)九杂、JVM系統環(huán)境屬性(JDK版本颁湖,JDK目錄等)、默認激活節(jié)點例隆、屬性解析器等甥捺。

StandardEnvironment初始化

public class StandardEnvironment extends AbstractEnvironment {

    /** 系統環(huán)境屬性 System environment property source name: {@value}. */
    public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";

    /** JVM系統環(huán)境屬性 JVM system properties property source name: {@value}. */
    public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";


    /**
     * Customize the set of property sources with those appropriate for any standard
     * Java environment:
     * <ul>
     * <li>{@value #SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME}
     * <li>{@value #SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME}
     * </ul>
     * <p>Properties present in {@value #SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME} will
     * take precedence over those in {@value #SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME}.
     * @see AbstractEnvironment#customizePropertySources(MutablePropertySources)
     * @see #getSystemProperties()
     * @see #getSystemEnvironment()
     */
    @Override
    protected void customizePropertySources(MutablePropertySources propertySources) {
        // 主要通過System類來獲取信息

        // 獲取系統環(huán)境屬性并加入到propertySources中
        propertySources.addLast(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
        // 獲取JVM系統環(huán)境屬性并加入到propertySources中
        propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
    }

}

AbstractEnvironment初始化

private final MutablePropertySources propertySources = new MutablePropertySources();
private final ConfigurablePropertyResolver propertyResolver = new PropertySourcesPropertyResolver(this.propertySources);
public AbstractEnvironment() {
    customizePropertySources(this.propertySources);
}
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市镀层,隨后出現的幾起案子涎永,更是在濱河造成了極大的恐慌,老刑警劉巖鹿响,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異谷饿,居然都是意外死亡惶我,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進店門博投,熙熙樓的掌柜王于貴愁眉苦臉地迎上來绸贡,“玉大人,你說我怎么就攤上這事毅哗√拢” “怎么了?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵虑绵,是天一觀的道長尿瞭。 經常有香客問我,道長翅睛,這世上最難降的妖魔是什么声搁? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮捕发,結果婚禮上疏旨,老公的妹妹穿的比我還像新娘。我一直安慰自己扎酷,他們只是感情好檐涝,可當我...
    茶點故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般谁榜。 火紅的嫁衣襯著肌膚如雪幅聘。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天惰爬,我揣著相機與錄音喊暖,去河邊找鬼。 笑死撕瞧,一個胖子當著我的面吹牛陵叽,可吹牛的內容都是我干的。 我是一名探鬼主播丛版,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼巩掺,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了页畦?” 一聲冷哼從身側響起胖替,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎豫缨,沒想到半個月后独令,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡好芭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年燃箭,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片舍败。...
    茶點故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡招狸,死狀恐怖,靈堂內的尸體忽然破棺而出邻薯,到底是詐尸還是另有隱情裙戏,我是刑警寧澤,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布厕诡,位于F島的核電站累榜,受9級特大地震影響,放射性物質發(fā)生泄漏木人。R本人自食惡果不足惜信柿,卻給世界環(huán)境...
    茶點故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望醒第。 院中可真熱鬧渔嚷,春花似錦、人聲如沸稠曼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至漠吻,卻和暖如春量瓜,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背途乃。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工绍傲, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人耍共。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓烫饼,卻偏偏與公主長得像,于是被迫代替她去往敵國和親试读。 傳聞我的和親對象是個殘疾皇子杠纵,可洞房花燭夜當晚...
    茶點故事閱讀 44,689評論 2 354

推薦閱讀更多精彩內容