天天看點

Spring的循環依賴問題

spring容器循環依賴包括構造器循環依賴和setter循環依賴,那Spring容器如何解決循環依賴呢?首先讓我們來定義循環引用類:

在Spring中将循環依賴的處理分成了3種情況:

構造器循環依賴

setter循環依賴

prototype範圍的依賴處理

通過構造器注入構成的循環依賴,此依賴是無法解決的,隻能抛出BeanCurrentlyInCreationException異常表示循環依賴。

如在建立TestA類時,構造器需要TestB類,那将去建立TestB,在建立TestB類時又發現需要TestC類,則又去建立TestC,最終在建立TestC時發現又需要TestA,進而形成一個環,沒辦法建立。

Spring容器将每一個正在建立的bean辨別符放在一個"目前建立bean池"中,bean辨別符在建立過程中将一直保持在這個池中,是以如果在建立bean過程中發現自己已經在"目前建立bean池"裡時,将抛出BeanCurrentlyInCreationException異常表示循環依賴;而對于建立完畢的bean将從"目前建立bean池"中清除掉。

通過setter注入方式構成的循環依賴。對于setter注入造成的依賴是通過Spring容器提前暴露剛完成構造器注入但未完成其他步驟(如setter注入)的bean來完成的,而且隻能解決單例作用域的bean循環依賴。通過提前暴露一個單例工廠方法,進而使其他bean能引用到該bean。

Spring容器建立單例"testA"bean,首先根據無參構造器建立bean,并暴露一個"ObjectFactory"用于傳回一個提前暴露一個建立中的bean,并将"testA"辨別符放到"目前建立bean池",然後進行setter注入"testB"。

Spring容器建立單例"testB"bean,首先根據無參構造器建立bean,并暴露一個"ObjectFactory"用于傳回一個提前暴露一個建立中的bean,并将"testB"辨別符放到"目前建立bean池",然後進行setter注入"testC"。

Spring容器建立單例"testC"bean,首先根據無參構造器建立bean,并暴露一個"ObjectFactory"用于傳回一個提前暴露一個建立中的bean,并将"testC"辨別符放到"目前建立bean池",然後進行setter注入"testA"。進行注入"testA"時由于提前暴露了"ObjectFactory"工廠,進而使用它傳回提前暴露一個建立中的bean。

最後再依賴注入"testB"和"testA",完成setter注入。

對于"prototype"作用域bean,Spring容器無法完成依賴注入,因為Spring容器不進行緩存"prototype"作用域的bean,是以無法提前暴露一個建立中的bean。

對于"singleton"作用域bean,可以通過"setAllowCircularReferences(false);"來禁用循環引用。