Spring的核心機制依賴注入簡介
Spring能有效地組織J2EE應用各層的物件。不管是控制層的Action物件,還是業務層的Service物件,還是持久層的DAO物件,都可在Spring的管理下有機地協調、執行。
層的物件以松耦合的方式組織在一起,Action物件無須關心Service物件的具體實現,Service物件無須關心持久層物件的具體實現,各層物件的呼叫完全面向介面。當系統需要重構時,程式碼的改寫量將大大減少。
上面所說的一切都得宜於Spring的核心機制,依賴注入。依賴注入讓bean與bean之間以配置檔案組織在一起,而不是以硬編碼的方式耦合在一起。理解依賴注入
依賴注入(Dependency Injection)和控制反轉(Inversion of Control)是同一個概念。具體含義是:當某個角色(可能是一個Java例項,呼叫者)需要另一個角色(另一個Java例項,被呼叫者)的協助時,在傳統的程式設計過程中,通常由呼叫者來建立被呼叫者的例項。但在Spring裡,建立被呼叫者的工作不再由呼叫者來完成,因此稱為控制反轉;建立被呼叫者例項的工作通常由Spring容器來完成,然後注入呼叫者,因此也稱為依賴注入。
不管是依賴注入,還是控制反轉,都說明Spring採用動態、靈活的方式來管理各種物件。物件與物件之間的具體實現互相透明。在理解依賴注入之前,看如下這個問題在各種社會形態裡如何解決:一個人(Java例項,呼叫者)需要一把斧子(Java例項,被呼叫者)。
(1)原始社會里,幾乎沒有社會分工。需要斧子的人(呼叫者)只能自己去磨一把斧子(被呼叫者)。對應的情形為:Java程式裡的呼叫者自己建立被呼叫者。
(2)進入工業社會,工廠出現。斧子不再由普通人完成,而在工廠裡被生產出來,此時需要斧子的人(呼叫者)找到工廠,購買斧子,無須關心斧子的製造過程。對應Java程式的簡單工廠的設計模式。
(3)進入“按需分配”社會,需要斧子的人不需要找到工廠,坐在家裡發出一個簡單指令:需要斧子。斧子就自然出現在他面前。對應Spring的依賴注入。
第一種情況下,Java例項的呼叫者建立被呼叫的Java例項,必然要求被呼叫的Java類出現在呼叫者的程式碼裡。無法實現二者之間的松耦合。
第二種情況下,呼叫者無須關心被呼叫者具體實現過程,只需要找到符合某種標準(介面)的例項,即可使用。此時呼叫的程式碼面向介面程式設計,可以讓呼叫者和被呼叫者解耦,這也是工廠模式大量使用的原因。但呼叫者需要自己定位工廠,呼叫者與特定工廠耦合在一起。
第三種情況下,呼叫者無須自己定位工廠,程式執行到需要被呼叫者時,系統自動提供被呼叫者例項。事實上,呼叫者和被呼叫者都處於Spring的管理下,二者之間的依賴關係由Spring提供。
所謂依賴注入,是指程式執行過程中,如果需要呼叫另一個物件協助時,無須在程式碼中建立被呼叫者,而是依賴於外部的注入。Spring的依賴注入對呼叫者和被呼叫者幾乎沒有任何要求,完全支援對POJO之間依賴關係的管理。依賴注入通常有兩種:
·設值注入。
·構造注入
設值注入
設值注入是指透過setter方法傳入被呼叫者的例項。這種注入方式簡單、直觀,因而在Spring的依賴注入裡大量使用。看下面
//定義Person介面 public interface Person { //Person介面裡定義一個使用斧子的方法 public void useAxe(); } |
然後是Axe的介面
//定義Axe介面 public interface Axe { //Axe介面裡有個砍的方法 public void chop(); } |
Person的實現類
//Chinese實現Person介面 public class Chinese implements Person { //面向Axe介面 private Axe axe; //預設的構造器 public Chinese() {} //設值注入所需的setter方法 public void setAxe(Axe axe) { this.axe = axe; } //實現Person介面的useAxe方法 public void useAxe() { System.out.println(axe.chop()); } } |
Axe的第一個實現類
//Axe的第一個實現類 StoneAxe public class StoneAxe implements Axe { //預設構造器 public StoneAxe() {} //實現Axe介面的chop方法 public String chop() { return "石斧砍柴好慢"; } } |
下面採用Spring的配置檔案將Person例項和Axe例項組織在一起。配置檔案如下所示:
<!-- 下面是標準的XML檔案頭 --> <?xml version="1.0" encoding="gb2312"?> <!-- 下面一行定義Spring的XML配置檔案的dtd --> "> <!-- 以上三行對所有的Spring配置檔案都是相同的 --> <!-- Spring配置檔案的根元素 --> <BEANS> <!—定義第一bean,該bean的id是chinese, class指定該bean例項的實現類 --> <BEAN class=lee.Chinese id=chinese> <!-- property元素用來指定需要 |
<property name="axe"> <!-- 此處將另一個bean的引用注入給chinese bean --> <REF local="”stoneAxe”/"> </property> </BEAN> <!-- 定義stoneAxe bean --> <BEAN class=lee.StoneAxe id=stoneAxe /> </BEANS> |
從配置檔案中,可以看到Spring管理bean的靈巧性。bean與bean之間的
Spring會自動接管每個bean定義裡的property元素定義。Spring會在執行無引數的構造器後、建立預設的bean例項後,呼叫對應的setter方法為程式注入屬性值。property定義的屬性值將不再由該bean來主動建立、管理,而改為被動接收Spring的注入。
每個bean的id屬性是該bean的惟一標識,程式透過id屬性
下面看主程式部分:
public class BeanTest { //主方法,程式的入口 public static void main(String[] args)throws Exception { //因為是獨立的應用 ApplicationContext ctx = new FileSystemXmlApplicationContext("bean.xml"); //透過Person bean的id來獲取bean例項,面向介面程式設計,因此 //此處強制型別轉換為介面型別 Person p = (Person)ctx.getBean("chinese"); //直接執行Person的userAxe()方法。 p.useAxe(); } } |
程式的執行結果如下:
石斧砍柴好慢
主程式呼叫Person的useAxe()方法時,該方法的方法體內需要使用Axe的例項,但程式裡沒有任何地方將特定的Person例項和Axe例項耦合在一起。或者說,程式裡沒有為Person例項傳入Axe的例項,Axe例項由Spring在執行期間動態注入。
Person例項不僅不需要了解Axe例項的具體實現,甚至無須瞭解Axe的建立過程。程式在執行到需要Axe例項的時候,Spring建立了Axe例項,然後注入給需要Axe例項的呼叫者。Person例項執行到需要Axe例項的地方,
呼叫者不僅無須關心被呼叫者的實現過程,連工廠定位都可以省略(真是按需分配啊!)。下面也給出使用Ant編譯和執行該應用的簡單指令碼:
<?xml version="1.0"?> <!-- 定義編譯該 <PROJECT name="spring" default="." basedir="."> <!-- 定義編譯和執行該專案時所需的庫檔案 --> <PATH id=classpath> <!-- 該路徑下存放spring.jar和其他第三方類庫 --> <FILESET dir=....lib> <INCLUDE name="*.jar" /> </FILESET> <!-- 同時還需要引用已經編譯過的class檔案--> <PATHELEMENT path="." /> </PATH> <!-- 編譯全部的java檔案--> <TARGET description="Compile all source code" name="compile"> <!-- 指定編譯後的class檔案的存放位置 --> <JAVAC debug="true" destdir="."> deprecation="false" optimize="false" failonerror="true"> <!-- 指定需要編譯的原始檔的存放位置 --> <SRC path="." /> <!-- 指定編譯這些java檔案需要的類庫位置--> <CLASSPATH refid="classpath" /> </JAVAC> </TARGET> <!-- 執行特定的主程式 --> <TARGET description="run the main class" name="run" depends="compile"> <!-- 指定執行的主程式:lee.BeanTest。--> <JAVA failonerror="true" fork="yes" classname="lee.BeanTest"> <!-- 指定執行這些java檔案需要的類庫位置--> <CLASSPATH refid="classpath" /> </JAVA> </TARGET> </PROJECT> |
如果需要改寫Axe的實現類。或者說,提供另一個實現類給Person例項使用。Person介面、Chinese類都無須改變。只需提供另一個Axe的實現,然後對配置檔案進行簡單的修改即可。
Axe的另一個實現如下:
//Axe的另一個實現類 SteelAxe public class SteelAxe implements Axe { //預設構造器 public SteelAxe() {} //實現Axe介面的chop方法 public String chop() { return "鋼斧砍柴真快"; } } |
然後,修改原來的Spring配置檔案,在其中增加如下一行:
<!-- 定義一個steelAxe bean--> <BEAN class=lee.SteelAxe id=steelAxe /> |
該行重新定義了一個Axe的實現:SteelAxe。然後修改chinese bean的配置,將原來傳入stoneAxe的地方改為傳入steelAxe。也就是將
<REF local="”stoneAxe”/"> |
改成
<REF local="”steelAxe”/"> |
此時再次執行程式,將得到如下結果:
鋼斧砍柴真快
Person與Axe之間沒有任何程式碼耦合關係,bean與bean之間的依賴關係由Spring管理。採用setter方法為目標bean注入屬性的方式,稱為設值注入。
業務物件的更換變得相當簡單,物件與物件之間的依賴關係從程式碼裡分離出來,透過配置檔案動態管理。
構造注入
所謂構造注入,指透過建構函式來完成依賴關係的設定,而不是透過setter方法。對前面程式碼Chinese類做
//Chinese實現Person介面 public class Chinese implements Person { //面向Axe介面程式設計,而不是具體的實現類 private Axe axe; //預設的構造器 public Chinese() {} //構造注入所需的帶引數的構造器 public Chinse(Axe axe) { this.axe = axe; } //實現Person介面的useAxe方法 public void useAxe() { System.out.println(axe.chop()); } } |
此時無須Chinese類裡的setAxe方法,構造Person例項時,Spring為Person例項注入所
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/9294812/viewspace-927141/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 2.3 Spring的核心機制:依賴注入Spring依賴注入
- Angular 依賴注入機制實現原理的深入介紹Angular依賴注入
- spring 的依賴注入Spring依賴注入
- Spring依賴注入Spring依賴注入
- Spring依賴注入---Spring依賴注入
- .Net DI(Dependency Injection)依賴注入機制依賴注入
- Spring 依賴注入的理解Spring依賴注入
- Spring【依賴注入】就是這麼簡單Spring依賴注入
- 利用反射機制實現依賴注入的原理反射依賴注入
- Spring IOC——依賴注入Spring依賴注入
- Spring 依賴注入 DISpring依賴注入
- Spring的依賴注入的方式Spring依賴注入
- spring 依賴注入的學習Spring依賴注入
- Spring系列.依賴注入配置Spring依賴注入
- Spring.Net 依賴注入Spring依賴注入
- 大白話spring依賴注入Spring依賴注入
- 打造簡單的依賴注入功能依賴注入
- WinForm依賴注入簡單使用ORM依賴注入
- spring框架學習 依賴注入Spring框架依賴注入
- Spring依賴注入原理學習Spring依賴注入
- Spring學習(三)依賴注入Spring依賴注入
- Spring升級案例之IOC介紹和依賴注入Spring依賴注入
- Spring的三種依賴注入的方式Spring依賴注入
- Spring學習:簡單實現一個依賴注入和迴圈依賴的解決Spring依賴注入
- Maven依賴機制Maven
- spring常用的三種依賴注入方式Spring依賴注入
- 依賴注入?依賴注入是如何實現解耦的?依賴注入解耦
- 「Laravel 核心學習」類的反射和依賴注入Laravel反射依賴注入
- JavaScrpit 的簡單的依賴注入Java依賴注入
- 30個類手寫Spring核心原理之依賴注入功能(3)Spring依賴注入
- 死磕Spring原始碼-依賴注入Spring原始碼依賴注入
- Spring原始碼解析——依賴注入(二)Spring原始碼依賴注入
- Spring 控制反轉和依賴注入Spring依賴注入
- Spring原始碼系列:依賴注入-引言Spring原始碼依賴注入
- Spring系列第八講 依賴注入之手動注入Spring依賴注入
- Spring原始碼系列:依賴注入(三)-屬性注入Spring原始碼依賴注入
- ASP.NET Core中的依賴注入(2):依賴注入(DI)ASP.NET依賴注入
- 簡單歡樂的依賴注入函式依賴注入函式