天天看點

Spring實戰2:裝配bean—依賴注入的本質主要内容

spring的配置方法概覽 自動裝配bean 基于java配置檔案裝配bean 控制bean的建立和銷毀

任何一個成功的應用都是由多個為了實作某個業務目标而互相協作的元件構成的,這些元件必須互相了解、能夠互相協作完成工作。例如,在一個線上購物系統中,訂單管理元件需要與産品管理元件以及信用卡認證元件協作;這些元件還需要跟資料庫元件協作進而進行資料庫讀寫操作。

在spring應用中,對象無需自己負責查找或者建立與其關聯的其他對象,由容器負責将建立各個對象,并建立各個對象之間的依賴關系。例如,一個訂單管理元件需要使用信用卡認證元件,它不需要自己建立信用卡認證元件,隻需要定義它需要使用信用卡認證元件即可,容器會建立信用卡認證元件然後将該元件的引用注入給訂單管理元件。

建立各個對象之間協作關系的行為通常被稱為裝配(wiring),這就是依賴注入(di)的本質。

基于xml檔案的顯式裝配

基于java檔案的顯式裝配

隐式bean發現機制和自動裝配

絕大多數情況下,開發人員可以根據個人品味選擇這三種裝配方式中的一種。spring也支援在同一個項目中混合使用不同的裝配方式。

我的建議是:盡可能使用自動裝配,越少寫顯式的配置檔案越好;當你必須使用顯式配置時(例如,你要配置一個bean,但是該bean的源碼不是由你維護),盡可能使用類型安全、功能更強大的基于java檔案的裝配方式;最後,在某些情況下隻有xml檔案中才又你需要使用的名字空間時,再選擇使用基于xml檔案的裝配方式。

spring通過兩個特性實作自動裝配:

component scanning——spring自動掃描和建立應用上下文中的beans;

autowiring——spring自動建立bean之間的依賴關系;

這裡用一個例子來說明:假設你需要實作一個音響系統,該系統中包含cdplayer和compactdisc兩個元件,spring将自動發現這兩個bean,并将compactdisc的引用注入到cdplayer中。

首先建立cd的概念——compactdisc接口,如下所示:

compactdisc接口的作用是将cdplayer與具體的cd實作解耦合,即面向接口程式設計。這裡還需定義一個具體的cd實作,如下所示:

這裡最重要的是@component注解,它告訴spring需要建立sgtpeppers bean。除此之外,還需要啟動自動掃描機制,有兩種方法:基于xml配置檔案;基于java配置檔案,代碼如下(二選一):

建立soundsystem.xml配置檔案

在這個xml配置檔案中,使用<context:component-scan>标簽啟動component掃描功能,并可設定base-package屬性。

建立java配置檔案

在這個java配置檔案中有兩個注解值得注意:@configuration表示這個.java檔案是一個配置檔案;@componentscan表示開啟component掃描,并且可以設定basepackages屬性——spring将會設定該目錄以及子目錄下所有被@component注解修飾的類。

自動配置的另一個關鍵注解是@autowired,基于之前的兩個類和一個java配置檔案,可以寫個測試

運作測試,測試通過,說明@autowired注解起作用了:自動将掃描機制建立的compactdisc類型的bean注入到soundsystemtest這個bean中。

在spring上下文中,每個bean都有自己的id。在上一個小節的例子中并沒有提到這一點,但spring在掃描到sgtpeppers這個元件并建立對應的bean時,預設給它設定的id為sgtpeppers——是的,這個id就是将類名稱的首字母小寫。

如果你需要給某個類對應的bean一個特别的名字,則可以給@component注解傳入指定的參數,例如:

在之前的例子中,我們通過給@component注解傳入字元串形式的包路徑,來設定需要掃描指定目錄下的類并為之建立bean。

可以看出,basepackages是複數,意味着你可以設定多個目标目錄,例如:

這種字元串形式的表示雖然可以,但是不具備“類型安全”,是以spring也提供了更加類型安全的機制,即通過類或者接口來設定掃描機制的目标目錄,例如:

通過如上設定,會将cdplayer和dvdplayer各自所在的目錄作為掃描機制的目标根目錄。

如果應用中的對象是孤立的,并且互相之間沒有依賴關系,例如sgtpeppersbean,那麼這就夠了。

簡單得說,自動裝配的意思是讓spring從應用上下文中找到對應的bean的引用,并将它們注入到指定的bean。通過@autowired注解可以完成自動裝配。

例如,考慮下面代碼中的cdplayer類,它的構造函數被@autowired修飾,表明當spring建立cdplayer的bean時,會給這個構造函數傳入一個compactdisc的bean對應的引用。

還有别的實作方法,例如将@autowired注解作用在setcompactdisc()方法上:

或者是其他名字的方法上,例如:

更簡單的用法是,可以将@autowired注解直接作用在成員變量之上,例如:

隻要對應類型的bean有且隻有一個,則會自動裝配到該屬性上。如果沒有找到對應的bean,應用會抛出對應的異常,如果想避免抛出這個異常,則需要設定@autowired(required=false)。不過,在應用程式設計中,應該謹慎設定這個屬性,因為這會使得你必須面對nullpointerexception的問題。

如果存在多個同一類型的bean,則spring會抛出異常,表示裝配有歧義,解決辦法有兩個:(1)通過@qualifier注解指定需要的bean的id;(2)通過@resource注解指定注入特定id的bean;

通過下列代碼,可以驗證:compactdisc的bean已經注入到cdplayer的bean中,同時在測試用例中是将cdplayer的bean注入到目前測試用例。

java配置檔案不同于其他用于實作業務邏輯的java代碼,是以不能将java配置檔案業務邏輯代碼混在一起。一般都會給java配置檔案建立一個單獨的package。

實際上在之前的例子中我們已經實踐過基于java的配置檔案,看如下代碼:

@configuration注解表示這個類是配置類,之前我們是通過@componentscan注解實作bean的自動掃描和建立,這裡我們重點是學習如何顯式建立bean,是以首先将<code>@componentscan(basepackageclasses = {cdplayer.class, dvdplayer.class})</code>這行代碼去掉。

通過@bean注解建立一個spring bean,該bean的預設id和函數的方法名相同,即sgtpeppers。例如:

同樣,可以指定bean的id,例如:

可以利用java語言的表達能力,實作類似工廠模式的代碼如下:

最簡單的辦法是将被引用的bean的生成函數傳入到構造函數或者set函數中,例如:

看起來是函數調用,實際上不是:由于sgtpeppers()方法被@bean注解修飾,是以spring會攔截這個函數調用,并傳回之前已經建立好的bean——確定該sgtpeppers bean為單例。

假如有下列代碼:

如果把sgtpeppers()方法當作普通java方法對待,則cdplayerbean和anothercdplayerbean會持有不同的sgtpeppers執行個體——結合cdplayer的業務場景看:就相當于将一片cd同時裝入兩個cd播放機中,顯然這不可能。

預設情況下,spring中所有的bean都是單例模式,是以cdplayer和anothercdplayer這倆bean持有相同的sgtpeppers執行個體。

當然,還有一種更清楚的寫法:

這種情況下,cdplayer和anothercdplayer這倆bean持有相同的sgtpeppers執行個體,該執行個體的id為lonelyheartsclub。這種方法最值得使用,因為它不要求compactdisc bean在同一個配置檔案中定義——隻要在應用上下文容器中即可(不管是基于自動掃描發現還是基于xml配置檔案定義)。

這種是spring中最原始的定義方式,在此不再詳述。

通常,可能在一個spring項目中同時使用自動配置和顯式配置,而且,即使你更喜歡javaconfig,也有很多場景下更适合使用xml配置。幸運的是,這些配置方法可以混合使用。

首先明确一點:對于自動配置,它從整個容器上下文中查找合适的bean,無論這個bean是來自javaconfig還是xml配置。

通過@import注解導入其他的javaconfig,并且支援同時導入多個配置檔案;

通過@importresource注解導入xml配置檔案;

2.5.2 在xml配置檔案中應用javaconfig

通過&lt;import&gt;标簽引入其他的xml配置檔案;

通過&lt;bean&gt;标簽導入java配置檔案到xml配置檔案,例如

通常的做法是:無論使用javaconfig或者xml裝配,都要建立一個root configuration,即子產品化配置定義;并且在這個配置檔案中開啟自動掃描機制:<code>&lt;context:component-scan&gt;</code>或者<code>@componentscan</code>。

這一章中學習了spring 裝配bean的三種方式:自動裝配、基于java檔案裝配和基于xml檔案裝配。

由于自動裝配幾乎不需要手動定義bean,建議優先選擇自動裝配;如何必須使用顯式配置,則優先選擇基于java檔案裝配這種方式,因為相比于xml檔案,java檔案具備更多的能力、類型安全等特點;但是也有一種情況必須使用xml配置檔案,即你需要使用某個名字空間(name space),該名字空間隻在xml檔案中可以使用。

<a href="http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html" target="_blank">http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html</a>

<a href="http://www.jianshu.com/p/550171d82e70">— 主要内容:environmentsandprofilesconditionalbeandeclaration處理自動裝配的歧義bean的作用域thespringexpressionlanguage在裝配bean—依賴注入的本質一文中,我們探讨了spring的三種管理bean的方式:自動裝配、基于javaconfig、基于xml檔案。這篇文字将探讨一些spring中關于bean的管理的進階知識,這些技能你可能不會每天都用,但是非常重要。3.1environmentsandprofiles在軟體開發中,常常設</a>