天天看點

Spring幹貨集|Bean依賴你又覺得行了?(下)

2.2 setter注入

通過調用無參構造器或無參靜态工廠方法執行個體化bean後,通過容器在bean上調用setter方法來完成基于setter注入。

如下案例是一個不依賴于特定于容器的接口,基類或注解,而且隻能setter注入方式DI的POJO類。

Spring幹貨集|Bean依賴你又覺得行了?(下)

ApplicationContext為其管理的bean的提供了構造器和setter DI的支援。也支援在已認證構造器注入某些依賴後,還支援setter DI。可通過BeanDefinition的形式配置依賴項,将其與PropertyEditor執行個體結合使用,以将屬性從一種格式轉為另一種。但大多數開發者并非以程式設計方式直接使用這些類,而是使用

XML形式的 bean定義

帶注解的元件,即被@Component,@Controller等注解的類

基于Java的@Configuration類中的@Bean方法

然後将這些源在内部轉換為BeanDefinition執行個體,并用于加載整個IoC容器執行個體。

3 構造器注入還是 setter 注入呢?

這麼詳細地分别介紹完後,那麼到底哪種 DI 方式好呢?

由于可混用構造器和setter DI,是以将構造器用于強制性依賴項,并搭配将setter方法或配置方法用于可選依賴項是個很好的最佳實踐。

注意,可在setter方法上使用@Required注解,以使該屬性成為必需的依賴;但最好使用帶有程式設計式驗證的參數的構造器注入。

而且注意,Spring團隊推薦構造器注入,因為它可以讓開發者将應用的元件實作為不可變對象,并確定所需的依賴項不為null。此外,構造器注入的元件始終以完全初始化的狀态傳回給用戶端(調用)代碼。不過注意了哦,大量的構造器自變量是一種壞代碼,因為這意味着該類可能承擔了太多職責(違反單一職責的程式設計原則),應對其重構以更好地解決關注點的解耦問題。

Setter注入主要應僅用于可以在類中配置設定合理的預設值的可選依賴項。否則,必須在代碼使用依賴項的所有地方都執行判空檢查。setter注入的一個好處是,setter方法使該類的對象在以後可重新配置或注入。

使用對特定類最有意義的DI方案。有時,在處理沒有源代碼的第三方類庫時,将為你做出選擇。例如,若第三方類庫未公開任何setter方法,則構造器注入可能就是DI的唯一可用方案咯。

4 deponds-on 屬性有何用?

你以為這個東西面試沒人問?看圖!

Spring幹貨集|Bean依賴你又覺得行了?(下)

若一個bean是另一個的依賴,則通常意味着将一個bean設為另一個的屬性。通常可使用XML形式配置中繼資料中的<ref/>元素完成此操作。但有時bean之間的依賴關系不那麼直接。一個示例是何時需要觸發類中的靜态初始化器,例如用于資料庫驅動程式注冊。depends-on屬性可顯式強制初始化一或多個使用該元素的bean之前的bean。

看如下案例,使用depends-on屬性表示對單個bean的依賴關系:

Spring幹貨集|Bean依賴你又覺得行了?(下)
要表示對多個 bean 的依賴,請提供 bean 名稱清單作為依賴屬性的值(逗号、空格和分号都是有效的分隔符):
Spring幹貨集|Bean依賴你又覺得行了?(下)

depends-on屬性既可以指定一個 初始化期(initialization-time) 依賴項,也可指定一個對應的析構期(destruction-time)依賴項。在銷毀給定bean之前,首先銷毀定義與給定bean的依賴關系的依賴bean。是以,depends-on還可以用來控制關閉順序。

5 lazy-init屬性有何作用?

在預設的初始化過程中,ApplicationContext會及早地建立并配置所有的單例bean。一般來說,這種預執行個體化是有好處的,畢竟相比于若幹天後的亡羊補牢,這樣可立即發現配置或上下文環境的錯誤。

當然了,如果你的業務決定了不想要這種預設行為,也可将bean定義标記為延遲初始化來防止對單例bean的預執行個體化。延遲初始化的bean告訴IoC容器在首次請求時而不是在應用啟動階段就建立一個bean執行個體。

如下案例:

XML形式,通過<bean/>标簽内的lazy-init屬性控制

Spring幹貨集|Bean依賴你又覺得行了?(下)
注解形式
Spring幹貨集|Bean依賴你又覺得行了?(下)
無需多慮,預設值為true就是要延遲初始化。
Spring幹貨集|Bean依賴你又覺得行了?(下)

當上述的配置被  ApplicationContext 使用時,在 ApplicationContext 啟動時不會預執行個體化惰性bean,未使用該屬性的非惰性bean才會被預執行個體化。

不過需要注意的是,當lazy-init bean是未lazy-init的單例bean的依賴時,ApplicationContext在啟動階段還是會建立lazy-init bean,因為它必須要滿足單例的依賴關系,lazy-init bean會被注入到其它未lazy-init 的單例bean中。

另外如果需要,可通過<bean/>标簽内的 default-lazy-init 屬性控制容器級别的延遲初始化,案例如下:

Spring幹貨集|Bean依賴你又覺得行了?(下)
參考