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
的後設資料。這些配置後設資料可以通過XML
,Java
程式碼或者註解來指定。
對於每一個bean
,它的依賴表現形式是成員屬性,構造器引數,或者靜態工廠方法的引數。在bean
真正建立時,Spring
容器會提供這些依賴的物件。這些引數可能是需要設定的預設值,也可能是另外一個bean
的引用。
Spring
容器會驗證每個bean
的配置資訊。並且在bean
真正建立時才設定設定屬性值或者引數值。
在Spring
中,單例作用域的bean
會提前初始化,在Spring
容器建立時就進行了例項化。對於其他的作用域的bean
,則只在需要時才進行建立。之所以單例作用域的bean
會被提前初始化,主要是為了解決依賴檢查的問題,下文的迴圈依賴一節會詳細說明。
在Spring
內部會構建一個建立bean
的依賴圖,按照這依賴關係來建立Bean
。
迴圈依賴解決
如果使用建構函式注入,則不能有迴圈依賴的情況。如A
構造器依賴B
,同時B
也構造器依賴A
。Spring IoC
容器會在執行時檢測到迴圈依賴,拋BeanCurrentlyInCreationException
異常。一種解決辦法是通過setter
方法來解決迴圈依賴的情況。
Spring
會在容器載入時檢測配置問題,如引用不存在或者迴圈依賴。Spring
會在必要時才解析依賴,即儘可能晚的來解析依賴關係。延遲解析依賴可能導致後期請求獲取物件時報錯,如丟擲一個異常,如丟失指定物件或者屬性。這種配置的延遲的可見性導致的問題使得ApplicationContext
的實現要求單例作用域的bean
提前記性初始化。雖然會耗費記憶體和時間,因為並不是按需建立這些單例作用域的bean
,但是可以在ApplicationContext
建立時就可以發現配置問題。
下文會介紹通過指定bean
的可以通過配置來覆蓋預設的行為,使得單例作用域的bean
也是延遲初始化。
如果沒有迴圈依賴存在,則在注入依賴物件時,這些依賴的物件就已經初始化完成了。即如果A
依賴B
,則在A
初始化時,B
已經初始化完成了。也就是說,Bean
是在相關依賴設定完成,並且相關的生命週期方法呼叫完畢後,才算是完成了初始化。
bean的延遲初始化
預設情況下ApplicationContext
是提前初始化單例作用域的bean
,作為ApplicationContext
初始化的一部分。這樣可以儘快的發現配置問題。可以通過指定bean
的lazy-init="true"
,讓bean
在需要時才被初始化。
自動注入依賴
在Spring中可以自動注入依賴,可以減少指定屬性或者構造器引數,還可以隨著配置物件的變化來更新注入的物件。
自動注入依賴的模式有:通過名稱注入,通過型別注入,和通過構造器注入。
總結
本文總結了Spring
中的依賴管理的基本原理和常見的問題,具體的依賴注入配置語法還需要參考Spring
的官方文件來進行。