標籤:blog http ar io 使用 sp java on 檔案
IOC(inversion of control)控制反轉
在我們的程式中,要實現某個功能,我們都會用到兩個或兩個以上的類來協同完成,那麼在一個類中,我們就會要有它的合作類的引用,也就是說這個類依賴於別的類,這個合作類的擷取,將會有一下幾種不同的情況
依賴擷取的三種方式:
Java代碼
- 情況1.自己產生
-
- Class person{
-
- Eat(){
-
- Apple a=new Apple();
-
- }
-
- }
第一種方式:在person的eat()方法裡就把吃的水果寫死,從開始就建立對象,
缺點 :1.Person類必須依賴於Apple類,如果Apple類沒完成,則編譯都不能通過
2.不能再更改,當person想再吃別的水果的時候,無法進行修改
3.很難共用給其他人,只能單獨使用
4.person類要對Apple的整個生命週期負責,兩個類始終耦合在一起
Java代碼
- 情況2 通過中介得到
-
- Class person{
-
- Eat(String name){
-
- Apple a=(Apple)Fruitfactory.getInstance(“name”);
-
- }}
第二種方式:1.通過使用工程類,間接得到需要的對象
通過使用工程類,程式效果確實得到了改進,但是問題依然存在
缺點:1.每個子類的產生的程式碼都寫死在工廠類裡面了,如果要換個子類,則必須更改工廠類中的方法
2.面向介面編程,一般都會使用工廠類,一般每個介面都會對於一個工程類,當項目非常大的時候,則會有非常多的工廠類
Java代碼
- 情況3.直接被注入
- Class person{
-
- Eat(Fruit fruit){
-
- //apple為Fruit實作類別
-
- }
-
- }
第三種方式:只需要在外部傳入一個現成的對象給方法調用,不同的實現傳入不同的對象即可(感覺這麼說就是簡單的面向介面的編程的好處,具體優勢,請看後面)
在系統中,我們可以用一個外部的容器Container 來統一調配整個系統的運行,將對象的建立和擷取提取到外部容器,由外部容器為每個組件提供需要的組建.
例如:
在容器中建立Fruit類對象apple,
將Person類依賴的Fruit對象傳遞給Person類
將了這麼多,那麼,到底是控制的什麼被反轉了呢?
獲得依賴對象的方式被反轉了.
也就是說
將一個對象如何擷取它所依賴的對象這個任務的控制權反轉到外部容器中。對象的依賴都是在對象建立時,由負責協調整個系統中各個實體間關係的外部容器提供了。
瞭解了IOC的基本理念後
剩下的問題就是:怎麼樣把類中依賴的對象的引用傳遞給類?(我們把這種將依賴對象的引用傳遞給類的方式叫做注入)
接下來,我們需要研究,有幾種方法,可以把對象注入到類的內部
注入的三種方式:
1. 通過介面注入
這種方式要求我們自己定義的組建類必須實現容器給定的一個介面,然後容器通過這個介面,為我們的組建類注入所依賴的類
缺點:容器對組建的侵入性會很強,實現的組建只能給此容器用了,移植性不強
2. Setter注入
在容器中,通過調用對象的setter()方法,將該對象的依賴傳遞到類當中
3.構造器注入
通過使用構造器,在類初始化的時候,傳入對象的依賴
知道了在容器中可以有三種方式把一個類的對象的依賴傳入到這個對象的當中去,但是,這個類的對象我們到底該怎麼得到呢?它的依賴又該怎麼得到呢?
難道也是在容器中,簡單的通過new得到不同的對象,然後進行相互調用嗎?
如果是這樣的話,那麼我們僅僅只是完成了一些基於依賴倒轉的代碼重構工作而已,並沒有真正的體現系統的動態性
那麼我們該怎麼樣才能最大程度的體現系統的動態性? 怎麼樣才能最大程度的將兩個類之間的依賴降低,實現解耦合呢?
我們可以給系統一個XML的設定檔,
在該XML設定檔中,設定每個對象的相應的屬性資訊(即該類的具體依賴)
然後在系統中,解析XML檔案得到一個實體類obj類,obj類保留沒一個對象的配置資訊
然後根據反射原理,利用解析得到的obj類中資訊,動態組建組態對應的對象,並且調用對象的setter()方法,完成對該對象的注入,
因為XML只是一個符合一定格式要求的文字檔,
所以我們可以隨時更改XML檔案,而不修改原始碼
來得到我們需要的任何類型的任何一個對象,並完全對該對象的注入
使該對象的依賴得以進行,並能使系統最大程度的動態化,具有可拓展性
IoC核心理念:
1.在類當中不建立對象,在代碼中不直接與對象和服務串連
2.在設定檔中描述建立對象的方式,以及各個組件之間的聯絡
3.外部容器通過解析設定檔,通過反射來將這些聯絡在一起
The Hollywood principle:Don’t call us,we’ll call you.
即,所有組件都是被動的、不主動聯絡(調用)外部代碼,
要等著外部代碼的調用--------所有的組件的初始化和相互調用都由容器負責實現。
簡單的說,就是整個程式之間的關係,都由容器來控制:將程式的控制權反轉給容器,就是所謂的外轉
而在我們傳統代碼中,由程式碼直接控制
最後,使用一個比較形象的例子來最後闡述一次IOC的作用:
所謂IoC,對於spring架構來說,就是由spring來負責控制對象的生命週期和對象間的關係。這是什麼意思呢,舉個簡單的例子,我們是如何找女朋友的?常見的情況是,我們到處去看哪裡有長得漂亮身材又好的mm,然後打聽她們的興趣愛好、qq號、電話號、ip號、iq號………,想辦法認識她們,投其所好送其所要,然後嘿嘿……這個過程是複雜深奧的,我們必須自己設計和面對每個環節。傳統的程式開發也是如此,在一個對象中,如果要使用另外的對象,就必須得到它(自己new一個,或者從JNDI中查詢一個),使用完之後還要將對象銷毀(比如Connection等),對象始終會和其他的介面或類藕合起來。
那麼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就是通過反射來實現注入的。
附註:因為參考的文章和Blog太多,無法一一表示感謝.謹在此特別感謝CSDN部落格的it_man大神
和http://www.zhuoda.org/xiaoming/66303.html的作者
以及百度百科作者、維基百科作者
以及javaeye上的多為寫了ioc的兄弟
恩,IOC原理折騰了一天總算搞明白了。接下來自己動手寫個玩具Spring吧
IOC原理分析