Spring IoC 使用詳解
在Spring中,依賴注入(DI)模式實現了控制反轉(IoC)原理。讓我們通過一個例子來幫助理解依賴注入。我們先看到java版的例子,然后在此基礎上加上spring的功能。就例子而言,是相當地簡單。QuizMater接口暴露了popQuestion()方法。為了保持簡單性,QuizMaster將只生成一個問題。
/**
* QuizMaster.java
*/
package com.vaannila;
public interface QuizMaster {
public String popQuestion();
}
StrutsQuizMaster和SpringQuizMaster類實現了QuizMaster接口,它們各自生成struts和spring相關的問題。
/**
* StrutsQuizMaster.java
*/
package com.vaannila;
public class StrutsQuizMaster implements QuizMaster {
@Override
public String popQuestion() {
return "Are you new to Struts?";
}
}
/**
* SpringQuizMaster.java
*/
package com.vaannila;
public class SpringQuizMaster implements QuizMaster {
@Override
public String popQuestion() {
return "Are you new to Spring?";
}
}
有個QuizMasterService類向用戶顯示問題。QuizMasterService類關聯了QuizMaster接口。
/**
* QuizMasterService.java
*/
package com.vaannila;
public class QuizMasterService {
private QuizMaster quizMaster = new SpringQuizMaster();
public void askQuestion(){
System.out.println(quizMaster.popQuestion());
}
}
最后創建QuizProgram類來管理測驗。
/**
* QuizProgram.java
*/
package com.vaannila;
public class QuizProgram {
public static void main(String[] args) {
QuizMasterService quizMasterService = new QuizMasterService();
quizMasterService.askQuestion();
}
}
看上去相當的簡單,我們創建了QuizMasterService類的實例,并且調用了askQuestion()方法。當你執行program,期望的“Are you new to Spring?”將從控制臺打印出來。
再看看這個例子的類圖。綠色箭頭表示泛化,藍色箭頭表示關聯。

看的出來這種結構是緊密耦合在一起的。在QuizMasterService類中創建了QuizMaster的實例,如下所示。
private QuizMaster quizMaster = new SpringQuizMaster();
為了測驗精通struts的人,我們需要修改QuizMasterService成這樣:
private QuizMaster quizMaster = new StrutsQuizMaster();
因此耦合性是非常高的,這就是為什么要使用依賴注入來避免這種耦合。Spring框架提供了非常強大的容器來管理組件。容器就是基于控制反轉(IoC)理念并且實現了依賴注入。這些組件僅僅需要選擇一種接受資源的方式,容器會自動為組件推送資源。
下面我們替換為QuizMasterService類直接創建QuizMaster對象的方式,讓容器來承擔這項工作。替換了硬編碼,允許容器來注入需要的依賴項。
注入依賴使用setter或構造方法注入。下面看看怎樣使用setter來注入。
/**
* QuizMasterService.java
*/
package com.vaannila;
public class QuizMasterService {
private QuizMaster quizMaster;
public void setQuizMaster(QuizMaster quizMaster) {
this.quizMaster = quizMaster;
}
public void askQuestion(){
System.out.println(quizMaster.popQuestion());
}
}
QuizMaster的值使用setQuizMaster()方法設置。在QuizMasterService類中,QuizMaster對象沒有實例化,但仍然來訪問它。通常這樣做會拋出NullPointerException異常,但是容器已經實例化了這個對象,因此能很好的工作。
再作了這些改變之后,例子的類圖就變成這樣了。

圖中多了容器,它幫助注入依賴項。
在beans.xml文件中的beans配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="springQuizMaster" class="com.vaannila.SpringQuizMaster"></bean>
<bean id="strutsQuizMaster" class="com.vaannila.StrutsQuizMaster"></bean>
<bean id="quizMasterService" class="com.vaannila.QuizMasterService">
<property name="quizMaster">
<ref local="springQuizMaster" />
</property>
</bean>
</beans>
定義每個bean使用bean標簽。bean標簽的id屬性是獲取這個bean的邏輯名,class屬性表示了真實的bean類。property標簽指向bean的屬性。使用setter注入一個bean需要使用ref標簽。
SpringQuizMaster的引用被注入到QuizMasterbean。當我們執行這個例子,控制臺打印出“Are you new to Spring?”。
為了使QuizMaster問一個struts相關的問題,僅僅需要改變ref標簽的指向。
<bean id="quizMasterService" class="com.vaannila.QuizMasterService">
<property name="quizMaster">
<ref local="strutsQuizMaster" />
</property>
</bean>
依賴注入降低了組件之間的耦合。
要執行這個例子需要把如下的jar文件加大classpath。
antlr-runtime-3.0
commons-logging-1.0.4
org.springframework.asm-3.0.0.M3
org.springframework.beans-3.0.0.M3
org.springframework.context-3.0.0.M3
org.springframework.context.support-3.0.0.M3
org.springframework.core-3.0.0.M3
org.springframework.expression-3.0.0.M3