通過以上的學習,對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 Set fruits;
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。但本人水平有限,肯定有很多不當和不完整支持,期待共同進步,本文中的實例用到的代碼地址為:本文資源下載地址(免積分)