1. 程式人生 > >Java程序員必須掌握的Spring依賴管理原理

Java程序員必須掌握的Spring依賴管理原理

構造函數 關系 而且 dep 提前 覆蓋 配置問題 定義 deb

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的官方文檔來進行。

Java程序員必須掌握的Spring依賴管理原理