Java程式設計師必須掌握的Spring依賴管理原理

Protopia發表於2019-04-17

Spring依賴注入

依賴注入(Dependency Injection)的意思就是物件通過構造器函式引數,工廠方法的引數,或者成員屬性,定義了物件的依賴物件;容器在建立該物件時會負責注入這些依賴。這個過程是控制反轉的,即不是由即將建立的物件來管理自己的依賴的發現和例項化,而是有Spring容器來實現。

Spring中依賴注入有兩種形式,第一種就是基於建構函式的注入,即通過呼叫建構函式,傳入引數,也就是依賴來完成整個依賴注入流程;第二種就是基於setter方法的注入。

建構函式的引數的匹配,要避免歧義,如指定型別,指定引數的次序等。如果是按照引數名字匹配,則必須開啟debug模式進行編譯,否則引數名字是不保留的。如果不想開啟debug模式編譯,則可以使用@ConstructorProperties註解。

setter方法注入是先呼叫沒有引數的預設建構函式構建物件,或者沒有引數的靜態工廠方法,例項化bean後,呼叫setter方法來將該物件注入。

通過使用依賴注入,可以使程式碼更簡潔,更好地實現物件之間解耦。另外,通過依賴注入管理的的物件是POJO類,可以更好地進行測試。

如何選擇合適的依賴注入方法?

最佳實踐是通過構造器方法注入主要依賴物件,通過setter方法注入可選的依賴物件。雖然可以在setter方法上加上@Required註解來實現主要依賴物件注入,但一般還是推薦使用構造器注入必須的依賴。

使用構造器注入,可以使得應用的元件作為不可變的物件,而且可以保證注入依賴是非null的。另外,構造器注入返回的是一個完整的初始狀態的例項。但是,一般不推薦大量使用構造方法注入,如果出現這種情況,則說明程式碼需要重構。

setter方法適合注入可選的依賴,這些依賴可能有預設值,而且在其他位置使用這些依賴時務必要進行null值檢查。使用setter方法的一個好處是可以修改或者重新配置,或者需要時再注入。如基於JMX MBean的管理。

Spring依賴解析流程

首先ApplicationContext會被建立和初始化,會載入包括描述所有bean的後設資料。這些配置後設資料可以通過XMLJava程式碼或者註解來指定。

對於每一個bean,它的依賴表現形式是成員屬性,構造器引數,或者靜態工廠方法的引數。在bean真正建立時,Spring容器會提供這些依賴的物件。這些引數可能是需要設定的預設值,也可能是另外一個bean的引用。

Spring容器會驗證每個bean的配置資訊。並且在bean真正建立時才設定設定屬性值或者引數值。

Spring中,單例作用域的bean會提前初始化,在Spring容器建立時就進行了例項化。對於其他的作用域的bean,則只在需要時才進行建立。之所以單例作用域的bean會被提前初始化,主要是為了解決依賴檢查的問題,下文的迴圈依賴一節會詳細說明。

Spring內部會構建一個建立bean的依賴圖,按照這依賴關係來建立Bean

迴圈依賴解決

如果使用建構函式注入,則不能有迴圈依賴的情況。如A構造器依賴B,同時B也構造器依賴ASpring IoC容器會在執行時檢測到迴圈依賴,拋BeanCurrentlyInCreationException異常。一種解決辦法是通過setter方法來解決迴圈依賴的情況。

Spring會在容器載入時檢測配置問題,如引用不存在或者迴圈依賴。Spring會在必要時才解析依賴,即儘可能晚的來解析依賴關係。延遲解析依賴可能導致後期請求獲取物件時報錯,如丟擲一個異常,如丟失指定物件或者屬性。這種配置的延遲的可見性導致的問題使得ApplicationContext的實現要求單例作用域的bean提前記性初始化。雖然會耗費記憶體和時間,因為並不是按需建立這些單例作用域的bean,但是可以在ApplicationContext建立時就可以發現配置問題。

下文會介紹通過指定bean的可以通過配置來覆蓋預設的行為,使得單例作用域的bean也是延遲初始化。

如果沒有迴圈依賴存在,則在注入依賴物件時,這些依賴的物件就已經初始化完成了。即如果A依賴B,則在A初始化時,B已經初始化完成了。也就是說,Bean是在相關依賴設定完成,並且相關的生命週期方法呼叫完畢後,才算是完成了初始化。

bean的延遲初始化

預設情況下ApplicationContext是提前初始化單例作用域的bean,作為ApplicationContext初始化的一部分。這樣可以儘快的發現配置問題。可以通過指定beanlazy-init="true",讓bean在需要時才被初始化。

自動注入依賴

在Spring中可以自動注入依賴,可以減少指定屬性或者構造器引數,還可以隨著配置物件的變化來更新注入的物件。

自動注入依賴的模式有:通過名稱注入,通過型別注入,和通過構造器注入。

總結

本文總結了Spring中的依賴管理的基本原理和常見的問題,具體的依賴注入配置語法還需要參考Spring的官方文件來進行。

參考資料

  1. 官方文件-Dependencies

相關文章