循環依賴是多個類之間循環的嵌套引用,如果我們使用 new object 的方式發生循環依賴那麼程序會一直循環調用,直到內存溢出。那麼Spring 是怎麼處理循環依賴的呢?
先看看Spring Bean實例化過程
方式一 帶參數的構造函數
Spring容器會將每一個正在創建的 Bean 標識符放在一個 “當前創建Bean池” 中,Bean標識符在創建過程中會一直存在於這個池中。
因此如果在創建Bean過程中發現自己已經在 “當前創建Bean池” 的時候就會拋出 BeanCurrentlyInCreationException 表示循環依賴。成功創建完的 Bean 會從 “當前創建Bean池” 中清除掉。
方式二 單例中的setter方法
Spring Bean 在實例化過程中是先將Bean對象實例化之後再設置對象屬性,所以實例化不受影響。
Spring會將這個實例化完成的對象放到一個Map中,並且Spring提供了獲取這個未設置屬性的實例化對象引用的方法。
所以當Spring實例化了ObjectA、ObjectB、ObjectC後,緊接着會去設置對象的屬性,此時ObjectA依賴ObjectB,就會去Map中取出存在裏面的單例ObjectB對象,同理ObjectB取ObjectC,ObjectC取ObjectA,那麼不會出現問題。
方式三 多例中的setter方式
多例模式 scope=“prototype” 意味着每次請求都會創建一個實例對象。
兩者的區別是:有狀態的bean都使用Prototype作用域,無狀態的一般都使用singleton單例作用域。
對於“prototype”作用域Bean,Spring容器無法完成依賴注入,因爲“prototype”作用域的Bean,Spring容器不進行緩存,因此無法提前暴露一個創建中的Bean。