成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Spring 循環依賴:三級緩存的獨特優勢與二級緩存的局限

開發 前端
Spring?? 選擇使用三級緩存而不是二級緩存來解決循環依賴問題,是基于對 ??AOP?? 代理支持和遵循自身設計原則的綜合考量。

前言

在 Java 開發領域,Spring 框架以其強大的功能和高度的靈活性被廣泛應用。其中,循環依賴問題是 Spring 在 Bean 管理過程中必須妥善處理的關鍵挑戰之一。Spring 采用了獨特的三級緩存機制來有效應對這一難題。

什么是Spring的循環依賴

圖片圖片

循環依賴,簡單來說,就是兩個或多個 Bean 之間相互持有對方的引用,形成一個閉環。例如,Bean A 依賴于 Bean B,而 Bean B 又依賴于 Bean A,這就構成了一個典型的循環依賴場景。在 Spring 容器初始化這些 Bean 時,如果不能妥善處理循環依賴,將會導致程序陷入無限循環,無法完成 Bean 的創建與初始化,進而使應用程序無法正常啟動。

注意:

  • Spring解決循環依賴是有一定限制的:

首先就是要求互相依賴的Bean必須要是單例的Bean

另外就是依賴注入的方式不能都是構造函數注入的方式。

為什么只支持單例

Spring循環依賴的解決方案主要是通過對象的提前暴露來實現的。當一個對象在創建過程中需要引用到另一個正在創建的對象時,Spring會先提前暴露一個尚未完全初始化的對象實例,以解決循環依賴的問題。這個尚未完全初始化的對象實例就是半成品對象。

在 Spring 容器中,單例對象的創建和初始化只會發生一次,并且在容器啟動時就完成了。這意味著,在容器運行期間,單例對象的依賴關系不會發生變化。因此,可以通過提前暴露半成品對象的方式來解決循環依賴的問題。

相比之下,原型對象的創建和初始化可以發生多次,并且可能在容器運行期間動態地發生變化。因此,對于原型對象,提前暴露半成品對象并不能解決循環依賴的問題,因為在后續的創建過程中,可能會涉及到不同的原型對象實例,無法像單例對象那樣緩存并復用半成品對象。

因此,Spring只支持通過單例對象的提前暴露來解決循環依賴問題。

為什么不支持構造函數注入

Spring無法解決構造函數的循環依賴,是因為在對象實例化過程中,構造函數是最先被調用的,而此時對象還未完成實例化,無法注入一個尚未完全創建的對象,因此Spring容器無法在構造函數注入中實現循環依賴的解決。

什么是Spring的三級緩存

SpringBeanFactory體系中,BeanFactorySpring IoC容器的基礎接口,其DefaultSingletonBeanRegistry類實現了BeanFactory接口,并且維護了三級緩存:

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
  //一級緩存,保存完成的Bean對象
  private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
  //三級緩存,保存單例Bean的創建工廠
  private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
  //二級緩存,存儲"半成品"的Bean對象
  private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
}
  • singletonObjects是一級緩存,存儲的是完整創建好的單例bean對象。在創建一個單例bean時,會先從singletonObjects中嘗試獲取該bean的實例,如果能夠獲取到,則直接返回該實例,否則繼續創建該bean
  • earlySingletonObjects是二級緩存,存儲的是尚未完全創建好的單例bean對象。在創建單例bean時,如果發現該bean存在循環依賴,則會先創建該bean半成品對象,并將半成品對象存儲到earlySingletonObjects中。當循環依賴的bean創建完成后,Spring會將完整的bean實例對象存儲到singletonObjects中,并將earlySingletonObjects中存儲的代理對象替換為完整的bean實例對象。這樣可以保證單例bean的創建過程不會出現循環依賴問題。
  • singletonFactories是三級緩存,存儲的是單例bean的創建工廠。當一個單例bean被創建時,Spring會先將該bean的創建工廠存儲到singletonFactories中,然后再執行創建工廠的getObject()方法,生成該bean的實例對象。在該bean被其他bean引用時,Spring會從singletonFactories中獲取該bean的創建工廠,并將這個早期引用放入二級緩存earlySingletonObjects中,同時從三級緩存中移除BeanA的工廠對象。

以下是DefaultSingletonBeanRegistry#getSingleton方法,代碼中,包括一級緩存、二級緩存、三級緩存的處理邏輯,該方法是獲取bean的單例實例對象的核心方法:

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 首先從一級緩存中獲取bean實例對象,如果已經存在,則直接返回
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        // 如果一級緩存中不存在bean實例對象,而且當前bean正在創建中,則從二級緩存中獲取bean實例對象
        singletonObject = this.earlySingletonObjects.get(beanName);
        if (singletonObject == null && allowEarlyReference) {
            // 如果二級緩存中也不存在bean實例對象,并且允許提前引用,則需要在鎖定一級緩存之前,
            // 先鎖定二級緩存,然后再進行一系列處理
            synchronized (this.singletonObjects) {
                // 進行一系列安全檢查后,再次從一級緩存和二級緩存中獲取bean實例對象
                singletonObject = this.singletonObjects.get(beanName);
                if (singletonObject == null) {
                    singletonObject = this.earlySingletonObjects.get(beanName);
                    if (singletonObject == null) {
                        // 如果二級緩存中也不存在bean實例對象,則從三級緩存中獲取bean的ObjectFactory,并創建bean實例對象
                        ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                        if (singletonFactory != null) {
                            singletonObject = singletonFactory.getObject();
                            // 將創建好的bean實例對象存儲到二級緩存中
                            this.earlySingletonObjects.put(beanName, singletonObject);
                            // 從三級緩存中移除bean的ObjectFactory
                            this.singletonFactories.remove(beanName);
                        }
                    }
                }
            }
        }
    }
    return singletonObject;
}

二級緩存

圖片圖片

其實,使用二級緩存也能解決循環依賴的問題,一級緩存用于存儲已經完全初始化好的 Bean 實例,這些 Bean 可以直接被應用程序使用。二級緩存則存儲那些已經實例化,但尚未完成屬性注入和其他初始化操作的 Bean,即 半成品Bean

當 Spring 容器創建一個 Bean 時,首先會嘗試從一級緩存中獲取該 Bean。如果一級緩存中不存在,再去二級緩存中查找。若在二級緩存中找到,則返回這個 半成品Bean,等待后續完成剩余的初始化步驟。

但是如果完全依靠二級緩存解決循環依賴,意味著當我們依賴了一個代理類的時候,就需要在Bean實例化之后完成AOP代理。而在Spring的設計中,為了解耦Bean的初始化和代理,是通過AnnotationAwareAspectJAutoProxyCreator這個后置處理器來在Bean生命周期的最后一步來完成AOP代理的。

因為在Spring的初始化過程中,他是不知道哪些Bean可能有循環依賴的,那么,這時候Spring面臨兩個選擇:

  • 不管有沒有循環依賴,都提前把代理對象創建出來,并將代理對象緩存起來,出現循環依賴時,其他對象直接就可以取到代理對象并注入。
  • 不提前創建代理對象,在出現循環依賴時,再生成代理對象。這樣在沒有循環依賴的情況下,Bean就可以按著Spring設計原則的步驟來創建。

二級緩存看上去比較簡單,但是他也意味著Spring需要在所有的bean的創建過程中就要先生成代理對象再初始化,那么這就和Springaop的設計原則是相悖的。

  • AOP 代理問題:當 Bean 涉及 AOP 代理時,二級緩存的局限性就凸顯出來了。在 Spring 中,AOP 通過代理機制為 Bean 添加額外的功能,如事務管理、日志記錄等。在循環依賴場景下,如果使用二級緩存,可能會出現獲取到的 Bean 不是代理對象的情況。因為二級緩存中的 Bean 在被放入時,可能還未經過 AOP 代理處理。當其他 Bean 依賴這個未代理的 Bean 時,后續在使用該 Bean 的代理功能時就會出現問題,導致 AOP 功能無法正常發揮。
  • 破壞設計原則:Spring 的設計理念強調將 Bean 的創建和初始化過程進行解耦,以提高代碼的可維護性和擴展性。二級緩存機制在某些情況下可能會破壞這一設計原則。由于需要在 Bean 未完全初始化時就將其放入二級緩存,可能會導致在后續的初始化過程中,需要對這些 半成品Bean 進行額外的特殊處理,增加了代碼的復雜性和耦合度,不符合 Spring 設計的初衷。

圖片

Spring為了不破壞AOP的代理設計原則,則引入第三級緩存,在三級緩存中保存對象工廠,因為通過對象工廠我們可以在想要創建對象的時候直接獲取對象。有了它,在后續發生循環依賴時,如果依賴的BeanAOP代理,那么通過這個工廠獲取到的就是代理后的對象,如果沒有被AOP代理,那么這個工廠獲取到的就是實例化的真實對象。

總結

Spring 選擇使用三級緩存而不是二級緩存來解決循環依賴問題,是基于對 AOP 代理支持和遵循自身設計原則的綜合考量。三級緩存機制通過巧妙地分離 Bean 的實例化、初始化以及代理對象的創建過程,在復雜的循環依賴場景下,能夠確保 Bean 的正確創建和初始化,同時保證 AOP 功能的正常運行。

責任編輯:武曉燕 來源: 一安未來
相關推薦

2022-03-01 18:03:06

Spring緩存循環依賴

2022-12-02 12:01:30

Spring緩存生命周期

2009-09-23 09:37:07

Hibernate緩存

2023-12-12 17:44:13

三級緩存Bean

2022-01-12 07:48:19

緩存Spring 循環

2009-06-18 15:24:35

Hibernate二級

2022-05-08 19:23:28

Spring循環依賴

2009-09-21 14:59:31

Hibernate二級

2009-09-24 11:04:56

Hibernate二級

2013-09-08 23:30:56

EF Code Fir架構設計MVC架構設計

2024-03-04 08:47:17

Spring框架AOP

2009-09-21 13:31:10

Hibernate 3

2009-09-21 14:39:40

Hibernate二級

2009-06-10 15:00:58

Hibernate二級配置

2023-02-26 11:15:42

緩存循環依賴

2024-12-20 16:46:22

Spring三級緩存

2024-03-18 00:00:00

SpringBean設計

2025-04-29 07:06:20

2023-08-01 08:10:46

內存緩存

2009-08-13 18:12:12

Hibernate 3
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美日韩免费在线 | 久久精品久久精品 | 久久国产精品72免费观看 | 国产aa| 国产精品国产三级国产aⅴ入口 | 欧美一级片在线 | 国产三级电影网站 | 玖玖综合网 | 天天拍天天插 | 精品国产一区二区三区免费 | 丝袜毛片 | 一区二区三区国产 | 国产福利网站 | 999久久| 亚洲在线 | 中文字幕免费 | 久久久久久久久99精品 | 国产极品车模吞精高潮呻吟 | 欧美视频区 | 一区二区三区不卡视频 | 亚洲va国产日韩欧美精品色婷婷 | 欧美激情在线播放 | av国产精品 | 日韩综合在线 | 美女视频黄的 | 欧美高清免费 | 91综合网 | 天天爽天天干 | 久久r免费视频 | 一二三四在线视频观看社区 | 日韩欧美在线视频 | 久久精品亚洲成在人线av网址 | 久久久久久久亚洲精品 | 99re在线播放 | 精品在线一区二区三区 | 国产丝袜一区二区三区免费视频 | 亚洲一区免费 | 欧美精品久久久 | 国产精品福利网站 | 精品国产一区二区国模嫣然 | 亚洲二区视频 |