A對象中有B屬性,B對象中有A屬性。這就是循環(huán)依賴。我依賴你,你也依賴我。
比如:丈夫類Husband、妻子類Wife。Husband類中有Wife類的引用。Wife類中有Husband類的引用。
husband類中有wife
注意:里邊的toString方法對于wife這個屬性使用了getName()避免陷入死循環(huán)
public class Husband {private String name;
private Wife wife;
public void setName(String name) {this.name = name;
}
public void setWife(Wife wife) {this.wife = wife;
}
public String getName() {return name;
}
@Override
public String toString() {return "Husband{" +
"name='" + name + '\'' +
", wife=" + wife.getName() +
'}';
}
}
2、Wife類wife類中有husband
public class Wife {private String name;
private Husband husband;
@Override
public String toString() {return "Wife{" +
"name='" + name + '\'' +
", husband=" + husband.getName() +
'}';
}
public String getName() {return name;
}
public void setName(String name) {this.name = name;
}
public void setHusband(Husband husband) {this.husband = husband;
}
}
3、Spring配置文件配置兩個bean
4、測試類@Test
public void testDeprndency(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring2.xml");
Husband husband = applicationContext.getBean("husband", Husband.class);
System.out.println(husband);
Wife wife = applicationContext.getBean("wife", Wife.class);
System.out.println(wife);
}
5、測試結(jié)果6、結(jié)論singleotn + setter模式下的循環(huán)依賴 spring是沒有任何問題的。
singleotn 表示在整個Spring容器當中是單例的,獨一無二的。
singleotn + setter模式下的循環(huán)依賴 spring是如何應(yīng)對的?
主要原因是在這種模式下,Spring對Bean的管理主要分為清晰的兩個階段:
第一個階段:在Spring容器加載的時候,實例化Bean,只要其中任意一個Bean實例化之后,馬上進行“曝光”【不等屬性賦值就曝光】
第二個階段:Bean“曝光”之后,再進行屬性的賦值。
核心解決方案是:實例化對象和對象的屬性賦值分為兩個階段來完成的。
只有在scope是singleton的情況下,Bean才會采取提前“曝光”的措施
prototy+ setter模式下的循環(huán)依賴 spring是會出現(xiàn)異常的
Bean的循環(huán)依賴出現(xiàn)問題:BeanCurrentlyInCreationException
注意:當兩個Bean的scope都是prototype的時候,才會出現(xiàn)異常,如果其中任意一個是singleton,就不會出現(xiàn)異常
去掉set方法,加入構(gòu)造方法
public class Husband {private String name;
private Wife wife;
public Husband(String name, Wife wife) {this.name = name;
this.wife = wife;
}
public String getName() {return name;
}
@Override
public String toString() {return "Husband{" +
"name='" + name + '\'' +
", wife=" + wife.getName() +
'}';
}
}
2、Wife類去掉set方法,加入構(gòu)造方法
public class Wife {private String name;
private Husband husband;
public Wife(String name, Husband husband) {this.name = name;
this.husband = husband;
}
@Override
public String toString() {return "Wife{" +
"name='" + name + '\'' +
", husband=" + husband.getName() +
'}';
}
public String getName() {return name;
}
}
3、Spring配置文件構(gòu)造注入,這種循環(huán)依賴是否會出現(xiàn)問題?
4、測試類@Test
public void testDeprndency(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring2.xml");
Husband husband = applicationContext.getBean("husband", Husband.class);
System.out.println(husband);
Wife wife = applicationContext.getBean("wife", Wife.class);
System.out.println(wife);
}
5、運行結(jié)果
注意:基于構(gòu)造注入的方式下產(chǎn)生的循環(huán)依賴也是無法解決的
Spring只能解決set+singleton模式下的循環(huán)依賴。
三、Spring解決循環(huán)依賴的機理根本原因在于:這種方式可以做到將“實例化Bean”和“給Bean屬性賦值”這兩個動作分開去完成。
兩個步驟完全是可以分離開去完成的,并且不要求在同一時間點上完成。
也就是說Bean都是單例的,我們可以先把所有的單例Bean實例化出來,放到一個集合當中(緩存),所有的單例Bean全部實例化之后。我們再慢慢的調(diào)用setter方法給屬性賦值,這樣就解決了循環(huán)依賴的問題。
追源碼:
雙擊shift: AbstractAutowireCapableBeanFactory
ctrl + f :doCreateBean 方法
debug:
繼續(xù)往下走一步:
這個husband對象的name屬性和wife屬性是空的,但是這個對象已經(jīng)創(chuàng)建出來了
走到下一個斷點:
把這個單例對象緩存起來,具體看看怎么緩存的:
step into進去一個新的類:DefaultSingletonBeanRegistry
先說說這個類DefaultSingletonBeanRegistry中的三個比較重要的緩存:
private final MapsingletonObjects ------ 一級緩存
private final MapearlySingletonObjects ------ 二級緩存
private final Map>singletonFactories ------ 三級緩存
這三個緩存都是Map集合。Map集合的key存儲的都是bean的name(bean id)。
一級緩存存儲的是:完整的單例Bean對象。也就是說這個緩存中的Bean對象的屬性都已經(jīng)賦值了。是一個完整的Bean對象
二級緩存存儲的是:早期的單例Bean對象。這個緩存中的單例Bean對象的屬性沒有賦值,只是一個早期的實例對象
三級緩存存儲的是:單例工廠對象。這個里面存儲了大量的“工廠對象”,每一個單例Bean對象都會對應(yīng)一個單例工廠對象。這個集合中存儲的是:創(chuàng)建該單例對象時對應(yīng)的那個單例工廠對象
繼續(xù)回到debug:
進來DefaultSingletonBeanRegistry這個類之后addSingletonFactory這個方法執(zhí)行
繼續(xù)執(zhí)行到:
并沒有把Bean對象存進去,是把創(chuàng)建Bean對象的工廠對象存放到map集合。(三級緩存)
往map對象存的這個動作就叫做“曝光”
“曝光”工廠之后會繼續(xù)調(diào)用getSingleton方法
然后從一級緩存取對象,拿不到從二級緩存取,拿不到從三級緩存取,
三級緩存取工廠對象,獲取這個Bean對象,再把Bean對象放到二級緩存。
最后執(zhí)行
populateBean(beanName, mbd, instanceWrapper);才會給屬性賦值
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧
當前標題:spring之Bean的循環(huán)依賴問題-創(chuàng)新互聯(lián)
本文路徑:http://jinyejixie.com/article8/dsijop.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供Google、服務(wù)器托管、建站公司、關(guān)鍵詞優(yōu)化、微信公眾號、外貿(mào)建站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容