Spring鬆耦合示例html
最近公司須要,項目中要用到Spring和Ibatis。趁着過年好好學習學習。Ibatis就如同Hibernate同樣的持久層技術,學習起來難度不大,但Spring可不同,揣着Ioc,DJ和AOP,四處走紅。學起來可不容易。就市面上而言,就一本《expert one-on-one J2EE Development without EJB中文版》值得參考,爲了生活,再貴也得買。這本書的前五章都是說EJB的不是,從第六章開始進入正題,介紹控制反轉,之後基本都是說Spring了。java
可能本人比較愚笨,控制反轉弄得不明白。這樣就得上網上找答案了。最後在一個叫Bromon的blog上找到的淺顯易懂的答案。下面就是引用他說的話:spring
IoC與DI數據庫
首先想說說IoC(Inversion of Control,控制倒轉)。這是spring的核心,貫穿始終。所謂IoC,對於spring框架來講,就是由spring來負責控制對象的生命週期和 對象間的關係。這是什麼意思呢,舉個簡單的例子,咱們是如何找女友的?常見的狀況是,咱們處處去看哪裏有長得漂亮身材又好的mm,而後打聽她們的興趣愛 好、qq號、電話號、ip號、iq號………,想辦法認識她們,投其所好送其所要,而後嘿嘿……這個過程是複雜深奧的,咱們必須本身設計和麪對每一個環節。傳 統的程序開發也是如此,在一個對象中,若是要使用另外的對象,就必須獲得它(本身new一個,或者從JNDI中查詢一個),使用完以後還要將對象銷燬(比 如Connection等),對象始終會和其餘的接口或類藕合起來。json
那麼IoC是如何作的呢?有點像經過婚介找女友,在我和女友之間引入了一個第三者:婚姻介紹所。婚介管理了不少男男女女的資料,我能夠向婚 介提出一個列表,告訴它我想找個什麼樣的女友,好比長得像李嘉欣,身材像林熙雷,唱歌像周杰倫,速度像卡洛斯,技術像齊達內之類的,而後婚介就會按照我 們的要求,提供一個mm,咱們只須要去和她談戀愛、結婚就好了。簡單明瞭,若是婚介給咱們的人選不符合要求,咱們就會拋出異常。整個過程再也不由我本身控 制,而是有婚介這樣一個相似容器的機構來控制。Spring所倡導的開發方式就是如此,全部的類都會在spring容器中登記,告訴spring你是個什 麼東西,你須要什麼東西,而後spring會在系統運行到適當的時候,把你要的東西主動給你,同時也把你交給其餘須要你的東西。全部的類的建立、銷燬都由 spring來控制,也就是說控制對象生存週期的再也不是引用它的對象,而是spring。對於某個具體的對象而言,之前是它控制其餘對象,如今是全部對象 都被spring控制,因此這叫控制反轉。若是你還不明白的話,我決定放棄。框架
IoC的一個重點是在系統運行中,動態的向某個對象提供它所須要的其餘對象。這一點是經過DI(Dependency Injection,依賴注入)來實現的。好比對象A須要操做數據庫,之前咱們老是要在A中本身編寫代碼來得到一個Connection對象,有了 spring咱們就只須要告訴spring,A中須要一個Connection,至於這個Connection怎麼構造,什麼時候構造,A不須要知道。在系統 運行時,spring會在適當的時候製造一個Connection,而後像打針同樣,注射到A當中,這樣就完成了對各個對象之間關係的控制。A須要依賴 Connection才能正常運行,而這個Connection是由spring注入到A中的,依賴注入的名字就這麼來的。那麼DI是如何實現的呢? Java 1.3以後一個重要特徵是反射(reflection),它容許程序在運行的時候動態的生成對象、執行對象的方法、改變對象的屬性,spring就是經過反射來實現注入的。關於反射的相關資料請查閱java doc。post
我想經過Bromon的介紹,你們對IoC和DI都有了比較生動的理解了。再來看看《expert one-on-one J2EE Development without EJB中文版》是怎麼解釋這兩個概念的。書上是這麼說的:學習
IoC是一個很大的概念,能夠用不一樣的方式來實現。主要的實現形式有兩種:this
依賴查找:容器提供回調接口和上下文環境給組件。EJB和Apache Avalon都是使用這種方式。spa
依賴注入:組件不作定位查詢,只是提供普通的Java方法讓容器去決定依賴關係。容器全權負責組件的裝配,它會把符合依賴關係的對象經過JavaBean屬性或者構造子傳遞給須要的對象。經過JavaBean屬性注射依賴關係的作法稱爲設值方法注入(Setter Injection);將依賴關係做爲構造子參數傳入的作法稱爲構造子注入(Constructor Injection)。
面向對象設計的理念是把整個系統分紅一組可重用的組件,然而,當系統變得越大的時候,尤爲是在java中,這最大的對象依賴將會牢牢耦合,以致於很是難以管理和修改,而如今,你可使用Spring框架扮演一箇中間模塊的角色,方便高效地管理其餘組件依賴
看個例子,假設你的項目有一個方法能夠輸出內容到csv或者json格式,你可能寫出這樣的代碼
package com.mkyong.output; public interface IOutputGenerator { public void generateOutput(); }
,而後是實現接口的類
package com.mkyong.output.impl; import com.mkyong.output.IOutputGenerator; public class CsvOutputGenerator implements IOutputGenerator { public void generateOutput(){ System.out.println("Csv Output Generator"); } }
再寫個Json生成的類
package com.mkyong.output.impl; import com.mkyong.output.IOutputGenerator; public class JsonOutputGenerator implements IOutputGenerator { public void generateOutput(){ System.out.println("Json Output Generator"); } }
有好幾種方法來調用IOutputGenerator接口,以及咱們如何使用Spring來避免對象的過分耦合。
package com.mkyong.common; import com.mkyong.output.IOutputGenerator; import com.mkyong.output.impl.CsvOutputGenerator; public class App { public static void main( String[] args ) { IOutputGenerator output = new CsvOutputGenerator(); output.generateOutput(); } }
問題:
這種方法,output這個對象和CsvOutputGenerator耦合在了一塊兒,每次要改變輸出格式的話都要修改代碼,若是這類代碼遍及項目,那麼改起來就跪了
也許你會想建立一個Helper類吧全部的output實現都移進去
package com.mkyong.output; import com.mkyong.output.IOutputGenerator; import com.mkyong.output.impl.CsvOutputGenerator; public class OutputHelper { IOutputGenerator outputGenerator; public OutputHelper(){ outputGenerator = new CsvOutputGenerator(); } public void generateOutput(){ outputGenerator.generateOutput(); } }
而後能夠這樣調用
package com.mkyong.common; import com.mkyong.output.OutputHelper; public class App { public static void main( String[] args ) { OutputHelper output = new OutputHelper(); output.generateOutput(); } }
問題:
看起來彷佛更加優雅了,你僅僅須要管理這個Helper類就能夠實現不一樣格式的輸出需求改變了,然而,Helper仍是和CvsOutputGenerator耦合,每一次要改變輸出格式的時候,都要對Helper類作一下微調。
Spring依賴注入很合適,可使不一樣的格式生成類分離開來
首先對OutputHelper作一點微調,添加了一個參數
package com.mkyong.output; import com.mkyong.output.IOutputGenerator; public class OutputHelper { IOutputGenerator outputGenerator; public void generateOutput(){ outputGenerator.generateOutput(); } public void setOutputGenerator(IOutputGenerator outputGenerator){ this.outputGenerator = outputGenerator; } }
而後建立一個Spring bean配置文件,並聲明全部的Java對象依賴
<!-- Spring-Common.xml --> <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-2.5.xsd"> <bean id="OutputHelper" class="com.mkyong.output.OutputHelper"> <property name="outputGenerator" ref="CsvOutputGenerator" /> </bean> <bean id="CsvOutputGenerator" class="com.mkyong.output.impl.CsvOutputGenerator" /> <bean id="JsonOutputGenerator" class="com.mkyong.output.impl.JsonOutputGenerator" /> </beans>
而後經過Spring調用
package com.mkyong.common; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.mkyong.output.OutputHelper; public class App { public static void main( String[] args ) { ApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"Spring-Common.xml"}); OutputHelper output = (OutputHelper)context.getBean("OutputHelper"); output.generateOutput(); } }
之後要改Json格式,直接改一下xml配置文件就好了。可以減小錯誤
經過Spring框架的依賴注入,能夠優雅的管理對象依賴,更大的靈活性,尤爲是對於Java項目很是好用。