通過以上的學習,對spring容器和DI的概念應該比較清晰了,DI(依賴注入)作為spring的核心,spring當然提供了一套完善的機制來進行依賴注入。前篇文章從概念上介紹了依賴注入,本篇著重學習spring依賴注入的方法,這裡主要采用xml的方式。
構造器注入和設值注入是依賴注入的兩種主要方式,spring對此有很完善的實現,下面首先以代碼的形式進行簡要的說明。
Spring容器通過調用bean的構造函數(可能帶有幾個參數,每個參數代表一個依賴)完成構造器注入。通過靜態工廠方法和調用構造器及其類似,這裡一並進行說明。
Spring中構造器依賴注入采用以下的形式,每個參數用bean標簽的子標簽 < constructor-arg >進行配置:
.. .. ..
Index:在構造函數中參數的位置,從0開始
Value:參數值,通常是基本類型和 type或者index配合使用。
Name:構造函數中參數的名字
Ref:引用其他Spring管理的對象
Type:參數的類型,值為基本類型或者完全限定的類名。
下面采用代碼加注釋的形式分別對以上的配置項加以說明,引用的類庫見以前的文章,首先是簡單的代碼結構截圖:
Apple、Banana是用來演示ref配置項的,只是一個簡單的類,沒有任何字段。Fruit包含一個Apple和一個Banana,其代碼如下:
package com.test.wdi; /** * @date 2015-2-27 * @Description:此類主要是為了說明構造器注入的ref項,包含了基本的構造函數,靜態工廠方法,和實例工廠方法 */ public class Fruit { private Apple apple; private Banana banana; public Fruit() { super(); } /** * 靜態工廠方法 */ public static Fruit newInstance(Apple apple, Banana banana){ return new Fruit(apple, banana); } /** * 實例工廠方法 */ public Fruit newInstance1(Apple apple, Banana banana){ return new Fruit(apple, banana); } /** * 傳統帶參構造函數 */ public Fruit(Apple apple, Banana banana) { super(); this.apple = apple; this.banana = banana; } public Apple getApple() { return apple; } public void setApple(Apple apple) { this.apple = apple; } public Banana getBanana() { return banana; } public void setBanana(Banana banana) { this.banana = banana; } @Override public String toString() { return hashCode()+ "Fruit [apple=" + apple + ", banana=" + banana + "]"; } }
ExampleBean是用來演示除ref之外的其他配置項的,它有連個基本類型的字段,其代碼如下:
package com.test.wdi; /** * @date 2015-2-28 * @Description:此類用來說明構造器注入配置項中的 name index type value的,為了方便重寫了toString方法 */ public class ExampleBean { private int years; private String ultimateAnswer; private boolean test; public ExampleBean() { super(); } /** * 構造函數2,和構造函數1一樣具有兩個參數,如果bean配置中不加入type的限制, * 將會有和預期不一致的結果 */ public ExampleBean(int years, boolean test) { this.years = years; this.test = test; } /** * 構造函數1 */ public ExampleBean(int years, String ultimateAnswer) { this.years = years; this.ultimateAnswer = ultimateAnswer; } @Override public String toString() { return "ExampleBean [years=" + years + ", ultimateAnswer=" + ultimateAnswer + ", test=" + test + "]"; } }
Bean的配置,將依次說明
測試程序使用main函數,依次打印出來t1中定義的那些bean,代碼如下:
package com.test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * @Description: * 本示例例環境為eclipse */ public class TestMain { public static void main(String[] args) { /** * ApplicationContext代表spring容器,而ClassPathXmlApplicationContext是它的一個實現,它從類路徑下讀取相應的 * xml 元數據配置,並初始化容器。其中allbean.xml是相應的元數據配置 */ ApplicationContext context = new ClassPathXmlApplicationContext("allbean.xml"); //依次打印對象 System.out.println(context.getBean("f1")); System.out.println(context.getBean("f2")); System.out.println(context.getBean("f3")); System.out.println(context.getBean("exam1a")); System.out.println(context.getBean("exam1b")); System.out.println(context.getBean("exam2")); System.out.println(context.getBean("exam3")); System.out.println(context.getBean("exam4")); } }
測試結果如下截圖,均符合預期:
<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHA+16Kjurm51OzG99ei0uLQ6NKq16LS4tGtu7fSwMC1tcTOyszioaM8L3A+CjxoMj7J6CYjMjA1NDA716LI6zwvaDI+CjxwPsnoJiMyMDU0MDvXosjrysdzcHJpbmfI3cb31Nq199PDuf3O3rLOubnU7Lqvyv278tXfzt6yzrmks6e3vbeouvOjrMi7uvPNqLn9tffTw8bkc2V0dGVyt723qL340NDSwMC1tcTXosjroaM8L3A+CjxwPlNldNeiyOuxyL3PvPK1paOs1q7HsLXEzsTVwnNwcmluZ8jdxve6zcXk1sOz9cq2y/m+2bXEwP3X077NysdzZXR0ZXLXosjroaPPwsPmysfSu7bOeG1sxeTWw7yrxuTLtcP3o7o8L3A+CjxwPjwvcD4KPHByZSBjbGFzcz0="brush:java;">
依賴有多種類型,包含基本類型(int、double、string等)和復雜類型(系統類和自定義的類),下面依次說明它們在注入過程中需要注意的問題。
設置注入和構造器注入對應的標簽分別是
直接類型直接使用value子標簽或者屬性配置即可。Spring的conversion service 會自動把字符串轉化為真正的屬性(屬性或者構造函數參數)。
對應設置注入,由javabean規范和name屬性可以准確的確定類型,故轉換不存在問題。但是對於構造器注入,如果不對type或者name進行限制,可能會產生非預期結果。
如下一段配置實是上文中構造器中的一個片段,另外增加了設置注入加以比較。運行結果可以自行測試:
另外類型為java.util.properties可以采用類似下面的配置:
jdbc.driver.className=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/mydb
Idref子標簽只是一個把某個bean的id傳遞作為依賴傳遞給另外一個bean的防止錯誤的方式。通過只傳遞bean的id,可以構建構建更加靈活的程序。
基本的配置如下:
引用其他bean是spring中及其常見的場景,這種配置通過
基本樣式如下:
或者
以上兩者的區別是:前者在當前spring容器和父容器中尋找id(name)為someBean 的對象,而後者只在父容器中尋找。
而ref屬性是前者的簡寫。
下面看具體的例子:
在
Java的強大之處之一在於jdk提供了強大的集合框架,spring當然提供了注入集合的方法。
自從java1.5開始,支持泛型,我們的集合盡量使用泛型,另外關於集合合並涉及到bean定義的繼承,這裡暫不討論。
首先引入一個帶集合屬性的bean,省略了構造函數和get set方法。
public class FruitCollection { private Setfruits; private List fruitList; private Map fruitMap; private Properties ppp; }
具體見下面的配置代碼:
t1 t2 t3 t4
Spring支持注入null和字符串的空串,見如下的配置:
實際相當於分別執行了如下方法:
setUltimateAnswer(null); setUltimateAnswer("");
Spring的bean配置文件的格式除了以上用了多次的標准形式,還有一些簡單的縮略形式,這些縮略形式是基於xml命名空間,分別是p-nameplace和c-nameplace,依次對應seter注入和 構造器注入。
這裡不再贅述。直接貼一個spring官方文檔的示例來說明p命名空間:
嵌套的注入,fruit 有個apple屬性,假設apple 有個 color屬性。那麼可以在fruit的定義中直接為color注入屬性,前提是apple不為null:
本文從spring兩種依賴注入講起,然後舉出具體的配置例子依次講解到了大部門的注入實例,本文中大部分的例子均通過測試,環境為spring4.1.5。但本人水平有限,肯定有很多不當和不完整支持,期待共同進步,本文中的實例用到的代碼地址為:本文資源下載地址(免積分)