日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

Spring 解決循環依賴

作者:Ran959 更新時間: 2022-09-05 編程語言

1.什么是循環依賴?? ?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??

顧名思義:循環+依賴 ;

? ? ? ? - 類與類之間的依賴關系形成了閉環。

?常見的循環依賴有以下三種情況:

?- 自身依賴于自身

?- 互相循環依賴

?- 多組循環依賴

2.代碼演示依賴

public class YanshiTest {

    public static void main(String[] args) {
        new Test1();
    }
}
class Test1{
    private Test2 test2 = new Test2();
}

class Test2{
    private Test1 test1 = new Test1();
}

?Test1 依賴 Test2? ? ?Test2 依賴 Test1

我們執行代碼后結果:

Exception in thread "main" java.lang.StackOverflowError
	at com.ape.test.Test2.<init>(YanshiTest.java:21)
	at com.ape.test.Test1.<init>(YanshiTest.java:17)
	at com.ape.test.Test2.<init>(YanshiTest.java:21)
	at com.ape.test.Test1.<init>(YanshiTest.java:17)
	at com.ape.test.Test2.<init>(YanshiTest.java:21)
	at com.ape.test.Test1.<init>(YanshiTest.java:17)
	at com.ape.test.Test2.<init>(YanshiTest.java:21)
	at com.ape.test.Test1.<init>(YanshiTest.java:17)
	at com.ape.test.Test2.<init>(YanshiTest.java:21)
	at com.ape.test.Test1.<init>(YanshiTest.java:17)
	at com.ape.test.Test2.<init>(YanshiTest.java:21)
	at com.ape.test.Test1.<init>(YanshiTest.java:17)

這樣的循環循環了很多行才停,出現了StackOverflowError 的錯誤,這就是循環依賴。

3.如何解決

首先我們進行原因分析:

????????-? ?Test1在構造方法中需要獲取Test2的對象,然后在創建Test2中有需要Test1的對象。

解決問題的關鍵是我們要把對象的創建拆分為:

? ? ? ? -? 構造方法

? ? ? ? -? 成員變量賦值 ==》get/set 方法處理

首先先給Test1 與Test2 寫GET/SET方法

public class YanshiTest {
    public static void main(String[] args) {
        System.out.println( new Test1().getTest2());
    }
}
    class Test1{
        private Test2 test2;
        public Test2 getTest2() {
            return test2;
        }
        public void setTest2(Test2 test2) {
            this.test2 = test2;
        }
    }
    class Test2{
        private Test1 test1 ;

        public Test1 getTest1() {
            return test1;
        }

        public void setTest1(Test1 test1) {
            this.test1 = test1;
        }
    }

-??需要把構造方法與屬性賦值 作為一個整體?

-? 需要提供一個獲取實例的方法

? ? ? ? 這個方法需要 根據類型獲取一個對應的實例對象 因此定義為泛型

? ? ? ? 這個方法需要 完成構造? 完成成員變量的賦值

 public static <T> T getBean(Class<T> classname) throws Exception{
        //1.通過構造方法獲取實例對象
        Object t = classname.newInstance();
        //2.給成員變量賦值
        Field[] fields = classname.getDeclaredFields();
        //遍歷
        for (Field field : fields) {
            //賦值
            field.setAccessible(true);
            Class<?> type = field.getType();
            field.set(t,getBean(type));
        }
        return (T)t;
    }

此時我們在main方法進行調用還是會報錯,因此我們需要拆解來看

首先 我們想如果把獲取的實例對象存儲到Map容器 再去獲取需要的對象時,就不需要去new了,直接從map里面取出賦值給Test02,這樣就不會出現循環依賴了,但是這個map是個半成品,因此我們需要做一些操作:

 //存儲半成品的容器——解決循環依賴
    private static final Map<String,Object> map =new ConcurrentHashMap<String, Object>();

此時只需兩步

? ? ? ? 1.判斷map是否有對象

? ? ? ? 2.沒有就放進去

 public static <T> T getBean(Class<T> classname) throws Exception{
        //--獲取類型的名稱
        String beanName = classname.getSimpleName().toLowerCase();
        //--如果map中有對象直接返回
        if(map.containsKey(beanName)){
            return (T)map.get(beanName);
        }
        //1.通過構造方法獲取實例對象
        Object t = classname.newInstance();
        //--創建的這個半成品對象我們需要存儲在map容器中
        map.put(beanName,t);
        //2.給成員變量賦值
        Field[] fields = classname.getDeclaredFields();
        //遍歷
        for (Field field : fields) {
            //賦值
            field.setAccessible(true);
            Class<?> type = field.getType();
            field.set(t,getBean(type));
        }
        return (T)t;
    }

在進行運行:

?

解決掉了,完美撒花。? 解決這個的關鍵點在于提前暴露半成品對象。

上面的方法中的核心是getBean方法,Test1 創建后填充屬性時依賴Test2,那么就去創建 Test2,在創建 Test2 開始填充時發現依賴于 Test1,但此時 Test1 這個半成品對象已經有了(其實是個緩存),所以Test2可以正常創建,在通過遞歸把 Test1 也創建完整了。

3.循環依賴

基于前面案例的了解,我們知道肯定需要在調用構造方法方法創建完成后再暴露對象,在Spring中提供了三級緩存來處理這個事情:

首先在調用構造方法的后會放入到三級緩存中--》然后在填充屬性的時候會存入二級緩存中--》最后把創建的對象保存在了一級緩存中

就是這樣啦!下個星期見!

原文鏈接:https://blog.csdn.net/weixin_67588007/article/details/126215614

欄目分類
最近更新