Spring-bean的幾種循環依賴方式

Spring-bean的幾種循環依賴方式

什麼是循環依賴?java

循環依賴其實就是循環引用,也就是兩個或則兩個以上的bean互相持有對方,最終造成閉環。好比A依賴於B,B依賴於C,C又依賴於A。以下圖:spring

注意,這裏不是函數的循環調用,是對象的相互依賴關係。循環調用其實就是一個死循環,除非有終結條件。緩存

Spring中循環依賴場景有:性能優化

  • 構造器的循環依賴
  • setter方式單例,默認方式
  • setter方式原型,prototype

第一種:構造器參數循環依賴架構

Spring容器會將每個正在建立的Bean 標識符放在一個「當前建立Bean池」中,Bean標識符在建立過程當中將一直保持在這個池中。併發

所以若是在建立Bean過程當中發現本身已經在「當前建立Bean池」裏時將拋出BeanCurrentlyInCreationException異常表示循環依賴;而對於建立完畢的Bean將從「當前建立Bean池」中清除掉。app

首先咱們先初始化三個Bean。分佈式

Spring-bean的幾種循環依賴方式

Spring-bean的幾種循環依賴方式

Spring-bean的幾種循環依賴方式

OK,上面是很基本的3個類,,StudentA有參構造是StudentB。StudentB的有參構造是StudentC,StudentC的有參構造是StudentA ,這樣就產生了一個循環依賴的狀況,函數

咱們都把這三個Bean交給Spring管理,並用有參構造實例化。微服務

Spring-bean的幾種循環依賴方式

下面是測試類:

publicclassTest{

publicstaticvoidmain(String[] args){

ApplicationContext context =newClassPathXmlApplicationContext("com/zfx/student/applicationContext.xml");

//System.out.println(context.getBean("a", StudentA.class));

}

}

執行結果報錯信息爲:

Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException:

Error creating beanwithname'a': Requested beaniscurrentlyincreation:Isthere an unresolvable circular reference?

若是你們理解開頭那句話的話,這個報錯應該不驚訝,Spring容器先建立單例StudentA,StudentA依賴StudentB,而後將A放在「當前建立Bean池」中,此時建立StudentB,StudentB依賴StudentC ,而後將B放在「當前建立Bean池」中,此時建立StudentC,StudentC又依賴StudentA, 可是,此時Student已經在池中,因此會報錯,,由於在池中的Bean都是未初始化完的,因此會依賴錯誤 ,(初始化完的Bean會從池中移除)

第二種:setter方式單例,默認方式

若是要說setter方式注入的話,咱們最好先看一張Spring中Bean實例化的圖

Spring-bean的幾種循環依賴方式

如圖中前兩步驟得知:Spring是先將Bean對象實例化以後再設置對象屬性的

修改配置文件爲set方式注入

Spring-bean的幾種循環依賴方式

下面是測試類:

publicclassTest{

publicstaticvoidmain(String[] args){

ApplicationContext context =newClassPathXmlApplicationContext("com/zfx/student/applicationContext.xml");

System.out.println(context.getBean("a", StudentA.class));

}

}

打印結果爲:

com.zfx.student.StudentA@1fbfd6

爲何用set方式就不報錯了呢 ?

咱們結合上面那張圖看,

Spring先是用構造實例化

Bean對象 ,此時Spring會將這個實例化結束的對象放到一個Map中,而且Spring提供了獲取這個未設置屬性的實例化對象引用的方法。

結合咱們的實例來看,,當Spring實例化了StudentA、StudentB、StudentC後,緊接着會去設置對象的屬性,此時StudentA依賴StudentB,就會去Map中取出存在裏面的單例StudentB對象,以此類推,不會出來循環的問題嘍、

下面是Spring源碼中的實現方法。如下的源碼在Spring的Bean包中的DefaultSingletonBeanRegistry.java類中

Spring-bean的幾種循環依賴方式

第三種:setter方式原型,prototype

修改配置文件爲:

Spring-bean的幾種循環依賴方式

測試用例:

publicclassTest{

publicstaticvoidmain(String[] args){

ApplicationContext context =newClassPathXmlApplicationContext("com/zfx/student/applicationContext.xml");

//此時必需要獲取Spring管理的實例,由於如今scope="prototype" 只有請求獲取的時候纔會實例化對象

System.out.println(context.getBean("a", StudentA.class));

}

}

打印結果:

Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException:

Error creating beanwithname'a': Requested beaniscurrentlyincreation:Isthere an unresolvable circular reference?

爲何原型模式就報錯了呢 ?

對於「prototype」做用域Bean,Spring容器沒法完成依賴注入,由於「prototype」做用域的Bean,Spring容器不進行緩存,所以沒法提早暴露一個建立中的Bean。

感謝您耐心看完的文章

順便給你們推薦一個Java技術交流羣:710373545裏面會分享一些資深架構師錄製的視頻資料:有Spring,MyBatis,Netty源碼分析,高併發、高性能、分佈式、微服務架構的原理,JVM性能優化、分佈式架構等這些成爲架構師必備的知識體系。還能領取免費的學習資源,目前受益良多!

做者:摘星不想說話 連接:https://juejin.im/post/5ce25058e51d45105773e63f 來源:掘金 著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。
相關文章
相關標籤/搜索