Spring的核心技術(七)---迴圈依賴
迴圈依賴
如果使用構造器注入的方法,就可能會建立一個無法解析的迴圈依賴的場景。
例如:類A通過構造器注入需要類B的一個例項,並且類B通過構造器注入也需要一個類A的例項。如果對類A和B做了這樣的相互注入的配置,那麼Spring的IoC容器會在執行時檢查這種迴圈引用,並丟擲BeanCurrentlyInCreationException異常。
一種可能的解決是修改某些類的原始碼,通過Setter方法而不是構造器方法來注入依賴。或者避免使用構造器注入,只是用Setter注入。換句話說,雖然不推薦使用Setter方式來注入依賴,但這樣可以配置迴圈依賴。
跟典型的場景(沒有迴圈依賴)不同,迴圈依賴的兩個Bean會強制其中的一個注入到另一個優先完全自我初始化的Bean中(這是典型的雞生蛋,然後再蛋生雞的場景)。
通常我們會相信Spring會做正確的事情,如在容器載入時,它會檢查配置的問題,如引用了不存在的Bean和迴圈依賴。在實際建立Bean的時候,Spring會盡可能晚的來設定屬性和解決依賴問題。這就意味著即使在Spring容器正常載入之後,也會產生物件建立不了或依賴不足等異常。例如相關的Bean會丟擲不存在或無效屬性之類的異常。這種方式導致某些配置問題延遲暴露,所以預設情況下ApplicationContext實現提前例項化單例模式的Bean。在實際使用相關Bean之前就建立這些Bean,會支付一些時間和記憶體的成本,但這樣會在建立ApplicationContext時就發現配置問題,而不至於發現的較晚。這種預設的行為是可以重寫的,以便讓單例模式的Bean在需要時才例項化,而不是提取例項化。
如果沒有迴圈依賴存在,在一個或多個合作用的Bean被注入到一個依賴Bean中時,每個合作用的Bean要完全配置在被注入的依賴Bean之前。這就意味著,如果Bean A依賴於Bean A,那麼Spring的IoC容器在呼叫Bean A上的Setter方法之前要完全的配置Bean B。換句話說,例項化相關的Bean的時候(不是提取例項化單例),它所依賴的設定、以及相關的生命週期方法(如配置初始化方法或初始化Bean的回撥方法)都要被呼叫。