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