隨筆 - 63  文章 - 0  trackbacks - 0
          <2009年4月>
          2930311234
          567891011
          12131415161718
          19202122232425
          262728293012
          3456789

          常用鏈接

          留言簿(2)

          隨筆分類

          隨筆檔案

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          Spring的模塊化是很強(qiáng)的,各個功能模塊都是獨(dú)立的,我們可以選擇的使用。這一章先從Spring的IoC開始。所謂IoC就是一個用XML來定義生成對象的模式,我們看看如果來使用的。

             數(shù)據(jù)模型

             1、如下圖所示有三個類,Human(人類)是接口,Chinese(中國人)是一個子類,American(美國人)是另外一個子類。

          源代碼如下:

          java 代碼
          1. package cn.com.chengang.spring;   
          2. public interface Human {   
          3. void eat();   
          4. void walk();   
          5. }   
          6.   
          7. package cn.com.chengang.spring;   
          8. public class Chinese implements Human {   
          9. /* (非 Javadoc)  
          10. * @see cn.com.chengang.spring.Human#eat()  
          11. */  
          12. public void eat() {   
          13. System.out.println("中國人對吃很有一套");   
          14. }   
          15.   
          16. /* (非 Javadoc)  
          17. * @see cn.com.chengang.spring.Human#walk()  
          18. */  
          19. public void walk() {   
          20. System.out.println("中國人行如飛");   
          21. }   
          22. }   
          23.   
          24. package cn.com.chengang.spring;   
          25. public class American implements Human {   
          26. /* (非 Javadoc)  
          27. * @see cn.com.chengang.spring.Human#eat()  
          28. */  
          29. public void eat() {   
          30. System.out.println("美國人主要以面包為主");   
          31. }   
          32.   
          33. /* (非 Javadoc)  
          34. * @see cn.com.chengang.spring.Human#walk()  
          35. */  
          36. public void walk() {   
          37. System.out.println("美國人以車代步,有四肢退化的趨勢");   
          38. }   
          39. }  

           

          2、對以上對象采用工廠模式的用法如下

             創(chuàng)建一個工廠類Factory,如下。這個工廠類里定義了兩個字符串常量,所標(biāo)識不同的人種。getHuman方法根據(jù)傳入?yún)?shù)的字串,來判斷要生成什么樣的人種。

          java 代碼
          1. package cn.com.chengang.spring;   
          2. public class Factory {   
          3. public final static String CHINESE = "Chinese";   
          4. public final static String AMERICAN = "American";   
          5.   
          6. public Human getHuman(String ethnic) {   
          7. if (ethnic.equals(CHINESE))   
          8. return new Chinese();   
          9. else if (ethnic.equals(AMERICAN))   
          10. return new American();   
          11. else  
          12. throw new IllegalArgumentException("參數(shù)(人種)錯誤");   
          13. }   
          14. }  

           

          下面是一個測試的程序,使用工廠方法來得到了不同的“人種對象”,并執(zhí)行相應(yīng)的方法。

          java 代碼
          1. package cn.com.chengang.spring;   
          2. public class ClientTest {   
          3. public static void main(String[] args) {   
          4. Human human = null;   
          5. human = new Factory().getHuman(Factory.CHINESE);   
          6. human.eat();   
          7. human.walk();   
          8. human = new Factory().getHuman(Factory.AMERICAN);   
          9. human.eat();   
          10. human.walk();   
          11. }   
          12. }  

           

           3、采用Spring的IoC的用法如下:

             在項目根目錄下創(chuàng)建一個bean.xml文件

          xml 代碼
          1. <?xml version="1.0" encoding="UTF-8"?>   
          2. <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">   
          3. <beans>   
          4. <bean id="Chinese" class="cn.com.chengang.spring.Chinese"/>   
          5. <bean id="American" class="cn.com.chengang.spring.American"/>   
          6. </beans>  

          修改ClientTest程序如下:

          java 代碼
          1. package cn.com.chengang.spring;   
          2. import org.springframework.context.ApplicationContext;   
          3. import org.springframework.context.support.FileSystemXmlApplicationContext;   
          4. public class ClientTest {   
          5. public final static String CHINESE = "Chinese";   
          6. public final static String AMERICAN = "American";   
          7.   
          8. public static void main(String[] args) {   
          9. // Human human = null;   
          10. // human = new Factory().getHuman(Factory.CHINESE);   
          11. // human.eat();   
          12. // human.walk();   
          13. // human = new Factory().getHuman(Factory.AMERICAN);   
          14. // human.eat();   
          15. // human.walk();   
          16.   
          17. ApplicationContext ctx = new FileSystemXmlApplicationContext("bean.xml");   
          18. Human human = null;   
          19. human = (Human) ctx.getBean(CHINESE);   
          20. human.eat();   
          21. human.walk();   
          22. human = (Human) ctx.getBean(AMERICAN);   
          23. human.eat();   
          24. human.walk();   
          25. }   
          26. }  

           從這個程序可以看到,ctx就相當(dāng)于原來的Factory工廠,原來的Factory就可以刪除掉了。然后又把Factory里的兩個常量移到了ClientTest類里,整個程序結(jié)構(gòu)基本一樣。

             再回頭看原來的bean.xml文件的這一句:

          <bean id="Chinese" class="cn.com.chengang.spring.Chinese"/>

             id就是ctx.getBean的參數(shù)值,一個字符串。class就是一個類(包名+類名)。然后在ClientTest類里獲得Chinese對象就是這么一句

          human = (Human) ctx.getBean(CHINESE);

             因為getBean方法返回的是Object類型,所以前面要加一個類型轉(zhuǎn)換。

             總結(jié)

             (1)也許有人說,IoC和工廠模式不是一樣的作用嗎,用IoC好象還麻煩一點。

             舉個例子,如果用戶需求發(fā)生變化,要把Chinese類修改一下。那么前一種工廠模式,就要更改Factory類的方法,并且重新編譯布署。而IoC只需要將class屬性改變一下,并且由于IoC利用了Java反射機(jī)制,這些對象是動態(tài)生成的,這時我們就可以熱插撥Chinese對象(不必把原程序停止下來重新編譯布署)

             (2)也許有人說,即然IoC這么好,那么我把系統(tǒng)所有對象都用IoC方式來生成。

             注意,IoC的靈活性是有代價的:設(shè)置步驟麻煩、生成對象的方式不直觀、反射比正常生成對象在效率上慢一點。因此使用IoC要看有沒有必要,我認(rèn)為比較通用的判斷方式是:用到工廠模式的地方都可以考慮用IoC模式。

             (3)在上面的IoC的方式里,還有一些可以變化的地方。比如,bean.xml不一定要放在項目錄下,也可以放在其他地方,比如cn.com.chengang.spring包里。不過在使用時也要變化一下,如下所示:

          new FileSystemXmlApplicationContext("src/cn/com/chengang/spring/bean.xml");

             另外,bean.xml也可以改成其他名字。這樣我們在系統(tǒng)中就可以分門別類的設(shè)置不同的bean.xml。

             (4)關(guān)于IoC的低侵入性。

             什么是低侵入性?如果你用過Struts或EJB就會發(fā)現(xiàn),要繼承一些接口或類,才能利用它們的框架開發(fā)。這樣,系統(tǒng)就被綁定在Struts、EJB上了,對系統(tǒng)的可移植性產(chǎn)生不利的影響。如果代碼中很少涉及某一個框架的代碼,那么這個框架就可以稱做是一個低侵入性的框架。

             Spring的侵入性很低,Humen.java、Chinese.java等幾個類都不必繼承什么接口或類。但在ClientTest里還是有一些Spring的影子:FileSystemXmlApplicationContext類和ctx.getBean方式等。
          現(xiàn)在,低侵入性似乎也成了判定一個框架的實現(xiàn)技術(shù)好壞的標(biāo)準(zhǔn)之一。

             (5)關(guān)于bean.xml的用法

             bean.xml的用法還有很多,其中內(nèi)容是相當(dāng)豐富的。假設(shè)Chinese類里有一個humenName屬性(姓名),那么原的bean.xml修改如下。此后生成Chinese對象時,“陳剛”這個值將自動設(shè)置到Chinese類的humenName屬性中。而且由于singleton為true這時生成Chinese對象將采用單例模式,系統(tǒng)僅存在一個Chinese對象實例。

          <?xml version="1.0" encoding="UTF-8"?>
          <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
          <beans>
          <bean id="Chinese" class="cn.com.chengang.spring.Chinese" singleton="true">
          <property name="humenName">
          <value>陳剛</value>
          </property>
          </bean>
          <bean id="American" class="cn.com.chengang.spring.American"/>
          </beans>

             關(guān)于bean.xml的其它用法,不再詳細(xì)介紹了,大家自己拿Spring的文檔一看就明白了。

           Spring能有效地組織J2EE應(yīng)用各層的對象。不管是控制層的Action對象,還是業(yè)務(wù)層的Service對象,還是持久層的DAO對象,都可在Spring的管理下有機(jī)地協(xié)調(diào)、運(yùn)行。Spring將各層的對象以松耦合的方式組織在一起,Action對象無須關(guān)心Service對象的具體實現(xiàn),Service對象無須關(guān)心持久層對象的具體實現(xiàn),各層對象的調(diào)用完全面向接口。當(dāng)系統(tǒng)需要重構(gòu)時,代碼的改寫量將大大減少。

            上面所說的一切都得宜于Spring的核心機(jī)制,依賴注入。依賴注入讓bean與bean之間以配置文件組織在一起,而不是以硬編碼的方式耦合在一起。理解依賴注入

            依賴注入(Dependency Injection)和控制反轉(zhuǎn)(Inversion of Control)是同一個概念。具體含義是:當(dāng)某個角色(可能是一個Java實例,調(diào)用者)需要另一個角色(另一個Java實例,被調(diào)用者)的協(xié)助時,在傳統(tǒng)的程序設(shè)計過程中,通常由調(diào)用者來創(chuàng)建被調(diào)用者的實例。但在Spring里,創(chuàng)建被調(diào)用者的工作不再由調(diào)用者來完成,因此稱為控制反轉(zhuǎn);創(chuàng)建被調(diào)用者實例的工作通常由Spring容器來完成,然后注入調(diào)用者,因此也稱為依賴注入。

            不管是依賴注入,還是控制反轉(zhuǎn),都說明Spring采用動態(tài)、靈活的方式來管理各種對象。對象與對象之間的具體實現(xiàn)互相透明。在理解依賴注入之前,看如下這個問題在各種社會形態(tài)里如何解決:一個人(Java實例,調(diào)用者)需要一把斧子(Java實例,被調(diào)用者)。

            (1)原始社會里,幾乎沒有社會分工。需要斧子的人(調(diào)用者)只能自己去磨一把斧子(被調(diào)用者)。對應(yīng)的情形為:Java程序里的調(diào)用者自己創(chuàng)建被調(diào)用者。

            (2)進(jìn)入工業(yè)社會,工廠出現(xiàn)。斧子不再由普通人完成,而在工廠里被生產(chǎn)出來,此時需要斧子的人(調(diào)用者)找到工廠,購買斧子,無須關(guān)心斧子的制造過程。對應(yīng)Java程序的簡單工廠的設(shè)計模式。

            (3)進(jìn)入“按需分配”社會,需要斧子的人不需要找到工廠,坐在家里發(fā)出一個簡單指令:需要斧子。斧子就自然出現(xiàn)在他面前。對應(yīng)Spring的依賴注入。

            第一種情況下,Java實例的調(diào)用者創(chuàng)建被調(diào)用的Java實例,必然要求被調(diào)用的Java類出現(xiàn)在調(diào)用者的代碼里。無法實現(xiàn)二者之間的松耦合。

            第二種情況下,調(diào)用者無須關(guān)心被調(diào)用者具體實現(xiàn)過程,只需要找到符合某種標(biāo)準(zhǔn)(接口)的實例,即可使用。此時調(diào)用的代碼面向接口編程,可以讓調(diào)用者和被調(diào)用者解耦,這也是工廠模式大量使用的原因。但調(diào)用者需要自己定位工廠,調(diào)用者與特定工廠耦合在一起。

            第三種情況下,調(diào)用者無須自己定位工廠,程序運(yùn)行到需要被調(diào)用者時,系統(tǒng)自動提供被調(diào)用者實例。事實上,調(diào)用者和被調(diào)用者都處于Spring的管理下,二者之間的依賴關(guān)系由Spring提供。

            所謂依賴注入,是指程序運(yùn)行過程中,如果需要調(diào)用另一個對象協(xié)助時,無須在代碼中創(chuàng)建被調(diào)用者,而是依賴于外部的注入。Spring的依賴注入對調(diào)用者和被調(diào)用者幾乎沒有任何要求,完全支持對POJO之間依賴關(guān)系的管理。依賴注入通常有兩種:

            ·設(shè)值注入。

            ·構(gòu)造注入。
          .......

          posted on 2009-04-06 00:13 lanxin1020 閱讀(714) 評論(0)  編輯  收藏 所屬分類: spring
          主站蜘蛛池模板: 临湘市| 屏东市| 华坪县| 九江县| 横山县| 利辛县| 营山县| 白朗县| 读书| 吉林市| 聊城市| 太仓市| 永泰县| 阜平县| 麦盖提县| 延长县| 广丰县| 台东县| 阳西县| 宝山区| 抚顺市| 湖南省| 隆昌县| 南平市| 德江县| 夏河县| 青冈县| 庆城县| 扎兰屯市| 临泽县| 林甸县| 商丘市| 东莞市| 砚山县| 巧家县| 陆河县| 新邵县| 休宁县| 涿鹿县| 武川县| 鹤庆县|