官术网_书友最值得收藏!

2.3.1 三級緩存結(jié)構(gòu)

所謂的三級緩存,在Spring中表現(xiàn)為三個Map對象,如代碼清單2-17所示。這三個Map對象定義在DefaultSingletonBeanRegistry類中,該類是DefaultListableBeanFactory的父類。

代碼清單2-17 DefaultSingletonBeanRegistry中的三級緩存Map定義代碼

/** 單例對象的緩存: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/** 單例對象工廠的緩存: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

/** 提前暴露的單例對象的緩存: bean name --> bean instance */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

請注意,這里的singletonObjects變量就是第一級緩存,用來持有完整的Bean實例。而earlySingletonObjects中存放的是那些提前暴露的對象,也就是已經(jīng)創(chuàng)建但還沒有完成屬性注入的對象,屬于第二級緩存。最后的singletonFactories存放用來創(chuàng)建earlySingleton-Objects的工廠對象,屬于第三級緩存。

那么,三級緩存是如何發(fā)揮作用的呢?讓我們來分析獲取Bean的代碼流程,如代碼清單2-18所示。

代碼清單2-18 獲取Bean的getSingleton()方法代碼

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    //首先從一級緩存singletonObjects中獲取
    Object singletonObject = this.singletonObjects.get(beanName);

    //如果獲取不到,就從二級緩存earlySingletonObjects中獲取
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
            singletonObject = this.earlySingletonObjects.get(beanName);

            //如果還是獲取不到,就從三級緩存singletonFactory中獲取
            if (singletonObject == null && allowEarlyReference) {
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    singletonObject = singletonFactory.getObject();

                    //一旦獲取成功,就把對象從第三級緩存移動到第二級緩存中
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}

看了這段代碼,我們不難理解對三級緩存的依次訪問過程,但可能還是不理解Spring為什么要這樣設(shè)計。事實上,解決循環(huán)依賴的關(guān)鍵還是要圍繞Bean的生命周期。在2.2.2節(jié)中介紹Bean的實例化時,我們知道它包含三個核心步驟,而在第一步和第二步之間,存在一個addSingletonFactory()方法,如代碼清單2-19所示。

代碼清單2-19 Bean實例化過程中的addSingletonFactory()方法代碼

//1. 初始化Bean,通過構(gòu)造函數(shù)創(chuàng)建Bean
instanceWrapper = createBeanInstance(beanName, mbd, args);

//針對循環(huán)依賴問題暴露單例工廠類
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

//2. 初始化Bean實例,完成Bean實例的完整創(chuàng)建
populateBean(beanName, mbd, instanceWrapper);

Spring解決循環(huán)依賴的訣竅就在于singletonFactories這個第三級緩存,上述addSingleton-Factory()方法用于初始化這個第三級緩存中的數(shù)據(jù),如代碼清單2-20所示。

代碼清單2-20 addSingletonFactory()方法代碼

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(singletonFactory, "Singleton factory must not be null");
    synchronized (this.singletonObjects) {
        if (!this.singletonObjects.containsKey(beanName)) {
            //添加Bean到第三級緩存中
            this.singletonFactories.put(beanName, singletonFactory);
            this.earlySingletonObjects.remove(beanName);
            this.registeredSingletons.add(beanName);
        }
    }
}

請注意,這段代碼的執(zhí)行時機是在已經(jīng)通過構(gòu)造函數(shù)創(chuàng)建Bean,但還沒有完成對Bean中完整屬性的注入的時候。換句話說,Bean已經(jīng)可以被暴露出來進(jìn)行識別了,但還不能正常使用。接下來我們就來分析一下為什么通過這種機制就能解決循環(huán)依賴問題。

主站蜘蛛池模板: 定结县| 连江县| 延吉市| 四子王旗| 报价| 镇雄县| 革吉县| 安岳县| 年辖:市辖区| 汪清县| 河曲县| 阿巴嘎旗| 比如县| 合川市| 洪湖市| 宜城市| 西乌珠穆沁旗| 周口市| 漳平市| 武宣县| 股票| 三门峡市| 稷山县| 商丘市| 宁河县| 三台县| 七台河市| 镇平县| 麻栗坡县| 娱乐| 祁东县| 宁夏| 封开县| 北宁市| 吉安市| 大港区| 大安市| 江门市| 临夏县| 卓资县| 林西县|