依賴注入原理---IoC框架

先來說一講,一個簡單的依賴注入例子。html

1. 依賴 若是在 Class A 中,有 Class B 的實例,則稱 Class A 對 Class B 有一個依賴。例以下面類 Human 中用到一個 Father 對象,咱們就說類 Human 對類 Father 有一個依賴。java

public class Human { ... Father father; ... public Human() { father = new Father(); } }

仔細看這段代碼咱們會發現存在一些問題:
(1). 若是如今要改變 father 生成方式,如須要用new Father(String name)初始化 father,須要修改 Human 代碼;
(2). 若是想測試不一樣 Father 對象對 Human 的影響很困難,由於 father 的初始化被寫死在了 Human 的構造函數中;
(3). 若是new Father()過程很是緩慢,單測時咱們但願用已經初始化好的 father 對象 Mock 掉這個過程也很困難。spring

2. 依賴注入 上面將依賴在構造函數中直接初始化是一種 Hard init 方式,弊端在於兩個類不夠獨立,不方便測試。咱們還有另一種 Init 方式,以下:docker

public class Human { ... Father father; ... public Human(Father father) { this.father = father; } }

上面代碼中,咱們將 father 對象做爲構造函數的一個參數傳入。在調用 Human 的構造方法以前外部就已經初始化好了 Father 對象。像這種非本身主動初始化依賴,而經過外部來傳入依賴的方式,咱們就稱爲依賴注入。
如今咱們發現上面 1 中存在的兩個問題都很好解決了,簡單的說依賴注入主要有兩個好處:
(1). 解耦,將依賴之間解耦。
(2). 由於已經解耦,因此方便作單元測試,尤爲是 Mock 測試。編程

 

接下來,深刻理解架構

 

1 IoC理論的背景
    咱們都知道,在採用面向對象方法設計的軟件系統中,它的底層實現都是由N個對象組成的,全部的對象經過彼此的合做,最終實現系統的業務邏輯。框架


 
圖1:軟件系統中耦合的對象編程語言


    若是咱們打開機械式手錶的後蓋,就會看到與上面相似的情形,各個齒輪分別帶動時針、分針和秒針順時針旋轉,從而在錶盤上產生正確的時間。圖1中描述的就是這樣的一個齒輪組,它擁有多個獨立的齒輪,這些齒輪相互齧合在一塊兒,協同工做,共同完成某項任務。咱們能夠看到,在這樣的齒輪組中,若是有一個齒輪出了問題,就可能會影響到整個齒輪組的正常運轉。
    齒輪組中齒輪之間的齧合關係,與軟件系統中對象之間的耦合關係很是類似。對象之間的耦合關係是沒法避免的,也是必要的,這是協同工做的基礎。如今,伴隨着工業級應用的規模愈來愈龐大,對象之間的依賴關係也愈來愈複雜,常常會出現對象之間的多重依賴性關係,所以,架構師和設計師對於系統的分析和設計,將面臨更大的挑戰。對象之間耦合度太高的系統,必然會出現牽一髮而動全身的情形。函數

 

 

 
圖2:對象之間複雜的依賴關係單元測試


    耦合關係不只會出如今對象與對象之間,也會出如今軟件系統的各模塊之間,以及軟件系統和硬件系統之間。如何下降系統之間、模塊之間和對象之間的耦合度,是軟件工程永遠追求的目標之一。爲了解決對象之間的耦合度太高的問題,軟件專家Michael Mattson提出了IOC理論,用來實現對象之間的「解耦」,目前這個理論已經被成功地應用到實踐當中,不少的J2EE項目均採用了IOC框架產品spring


2 什麼是控制反轉(IoC) 
    IOC是Inversion of Control的縮寫,多數書籍翻譯成「控制反轉」,還有些書籍翻譯成爲「控制反向」或者「控制倒置」。 
    1996年,Michael Mattson在一篇有關探討面向對象框架的文章中,首先提出了IOC 這個概念。對於面向對象設計及編程的基本思想,前面咱們已經講了不少了,再也不贅述,簡單來講就是把複雜系統分解成相互合做的對象,這些對象類經過封裝之後,內部實現對外部是透明的,從而下降了解決問題的複雜度,並且能夠靈活地被重用和擴展。IOC理論提出的觀點大致是這樣的:藉助於「第三方」實現具備依賴關係的對象之間的解耦,以下圖:

 


 圖3:IOC解耦過程


    你們看到了吧,因爲引進了中間位置的「第三方」,也就是IOC容器,使得A、B、C、D這4個對象沒有了耦合關係,齒輪之間的傳動所有依靠「第三方」了,所有對象的控制權所有上繳給「第三方」IOC容器,因此,IOC容器成了整個系統的關鍵核心,它起到了一種相似「粘合劑」的做用,把系統中的全部對象粘合在一塊兒發揮做用,若是沒有這個「粘合劑」,對象與對象之間會彼此失去聯繫,這就是有人把IOC容器比喻成「粘合劑」的由來。
咱們再來作個試驗:把上圖中間的IOC容器拿掉,而後再來看看這套系統:
 


圖4:拿掉IoC容器後的系統


    咱們如今看到的畫面,就是咱們要實現整個系統所須要完成的所有內容。這時候,A、B、C、D這4個對象之間已經沒有了耦合關係,彼此毫無聯繫,這樣的話,當你在實現A的時候,根本無須再去考慮B、C和D了,對象之間的依賴關係已經下降到了最低程度。因此,若是真能實現IOC容器,對於系統開發而言,這將是一件多麼美好的事情,參與開發的每一成員只要實現本身的類就能夠了,跟別人沒有任何關係!
    咱們再來看看,控制反轉(IOC)到底爲何要起這麼個名字?咱們來對比一下:
    軟件系統在沒有引入IOC容器以前,如圖1所示,對象A依賴於對象B,那麼對象A在初始化或者運行到某一點的時候,本身必須主動去建立對象B或者使用已經建立的對象B。不管是建立仍是使用對象B,控制權都在本身手上。
    軟件系統在引入IOC容器以後,這種情形就徹底改變了,如圖3所示,因爲IOC容器的加入,對象A與對象B之間失去了直接聯繫,因此,當對象A運行到須要對象B的時候,IOC容器會主動建立一個對象B注入到對象A須要的地方。
    經過先後的對比,咱們不難看出來:對象A得到依賴對象B的過程,由主動行爲變爲了被動行爲,控制權顛倒過來了,這就是「控制反轉」這個名稱的由來。

 

3 IOC的別名:依賴注入(DI) 
   2004年,Martin Fowler探討了同一個問題,既然IOC是控制反轉,那麼究竟是「哪些方面的控制被反轉了呢?」,通過詳細地分析和論證後,他得出了答案:「得到依賴對象的過程被反轉了」。控制被反轉以後,得到依賴對象的過程由自身管理變爲了由IOC容器主動注入。因而,他給「控制反轉」取了一個更合適的名字叫作「依賴注入(Dependency Injection)」。他的這個答案,實際上給出了實現IOC的方法:注入。所謂依賴注入,就是由IOC容器在運行期間,動態地將某種依賴關係注入到對象之中。

 

因此,依賴注入(DI)和控制反轉(IOC)是從不一樣的角度的描述的同一件事情,就是指經過引入IOC容器,利用依賴關係注入的方式,實現對象之間的解耦。
    咱們舉一個生活中的例子,來幫助理解依賴注入的過程。你們對USB接口和USB設備應該都很熟悉吧,USB爲咱們使用電腦提供了很大的方便,如今有不少的外部設備都支持USB接口。

 


圖6:USB接口和USB設備

 

    如今,咱們利用電腦主機和USB接口來實現一個任務:從外部USB設備讀取一個文件。
    電腦主機讀取文件的時候,它一點也不會關心USB接口上鍊接的是什麼外部設備,並且它確實也無須知道。它的任務就是讀取USB接口,掛接的外部設備只要符合USB接口標準便可。因此,若是我給電腦主機鏈接上一個U盤,那麼主機就從U盤上讀取文件;若是我給電腦主機鏈接上一個外置硬盤,那麼電腦主機就從外置硬盤上讀取文件。掛接外部設備的權力由我做主,即控制權歸我,至於USB接口掛接的是什麼設備,電腦主機是決定不了,它只能被動的接受。電腦主機須要外部設備的時候,根本不用它告訴我,我就會主動幫它掛上它想要的外部設備,你看個人服務是多麼的到位。這就是咱們生活中常見的一個依賴注入的例子。在這個過程當中,我就起到了IOC容器的做用。
    經過這個例子,依賴注入的思路已經很是清楚:當電腦主機讀取文件的時候,我就把它所要依賴的外部設備,幫他掛接上。整個外部設備註入的過程和一個被依賴的對象在系統運行時被注入另一個對象內部的過程徹底同樣。
咱們把依賴注入應用到軟件系統中,再來描述一下這個過程:
    對象A依賴於對象B,當對象 A須要用到對象B的時候,IOC容器就會當即建立一個對象B送給對象A。IOC容器就是一個對象製造工廠,你須要什麼,它會給你送去,你直接使用就好了,而不再用去關心你所用的東西是如何製成的,也不用關心最後是怎麼被銷燬的,這一切所有由IOC容器包辦。
    在傳統的實現中,由程序內部代碼來控制組件之間的關係。咱們常用new關鍵字來實現兩個組件之間關係的組合,這種實現方式會形成組件之間耦合。IOC很好地解決了該問題,它將實現組件間關係從程序內部提到外部容器,也就是說由容器在運行期將組件間的某種依賴關係動態注入組件中。

 

  4 IOC爲咱們帶來了什麼好處

     咱們仍是從USB的例子提及,使用USB外部設備比使用內置硬盤,到底帶來什麼好處?
     第1、USB設備做爲電腦主機的外部設備,在插入主機以前,與電腦主機沒有任何的關係,只有被咱們鏈接在一塊兒以後,二者才發生聯繫,具備相關性。因此,不管二者中的任何一方出現什麼的問題,都不會影響另外一方的運行。這種特性體如今軟件工程中,就是可維護性比較好,很是便於進行單元測試,便於調試程序和診斷故障。代碼中的每個Class均可以單獨測試,彼此之間互不影響,只要保證自身的功能無誤便可,這就是組件之間低耦合或者無耦合帶來的好處。
     第2、USB設備和電腦主機的之間無關性,還帶來了另一個好處,生產USB設備的廠商和生產電腦主機的廠商徹底能夠是互不相干的人,各幹各事,他們之間惟一須要遵照的就是USB接口標準。這種特性體如今軟件開發過程當中,好處但是太大了。每一個開發團隊的成員都只須要關心實現自身的業務邏輯,徹底不用去關心其它的人工做進展,由於你的任務跟別人沒有任何關係,你的任務能夠單獨測試,你的任務也不用依賴於別人的組件,不再用扯不清責任了。因此,在一個大中型項目中,團隊成員分工明確、責任明晰,很容易將一個大的任務劃分爲細小的任務,開發效率和產品質量必將獲得大幅度的提升。
     第3、同一個USB外部設備能夠插接到任何支持USB的設備,能夠插接到電腦主機,也能夠插接到DV機,USB外部設備能夠被反覆利用。在軟件工程中,這種特性就是可複用性好,咱們能夠把具備廣泛性的經常使用組件獨立出來,反覆利用到項目中的其它部分,或者是其它項目,固然這也是面向對象的基本特徵。顯然,IOC不只更好地貫徹了這個原則,提升了模塊的可複用性。符合接口標準的實現,均可以插接到支持此標準的模塊中。
     第4、同USB外部設備同樣,模塊具備熱插拔特性。IOC生成對象的方式轉爲外置方式,也就是把對象生成放在配置文件裏進行定義,這樣,當咱們更換一個實現子類將會變得很簡單,只要修改配置文件就能夠了,徹底具備熱插撥的特性。
以上幾點好處,難道還不足以打動咱們,讓咱們在項目開發過程當中使用IOC框架嗎?

5 IOC容器的技術剖析
    IOC中最基本的技術就是「反射(Reflection)」編程,目前.Net C#、Java和PHP5等語言均支持,其中PHP5的技術書籍中,有時候也被翻譯成「映射」。有關反射的概念和用法,你們應該都很清楚,通俗來說就是根據給出的類名(字符串方式)來動態地生成對象。這種編程方式可讓對象在生成時才決定究竟是哪種對象。反射的應用是很普遍的,不少的成熟的框架,好比象Java中的hibernate、Spring框架,.Net中 NHibernate、Spring.NET框架都是把「反射」作爲最基本的技術手段。
    反射技術其實很早就出現了,但一直被忽略,沒有被進一步的利用。當時的反射編程方式相對於正常的對象生成方式要慢至少得10倍。如今的反射技術通過改良優化,已經很是成熟,反射方式生成對象和一般對象生成方式,速度已經相差不大了,大約爲1-2倍的差距。
    咱們能夠把IOC容器的工做模式看作是工廠模式的昇華,能夠把IOC容器看做是一個工廠,這個工廠裏要生產的對象都在配置文件中給出定義,而後利用編程語言的的反射編程,根據配置文件中給出的類名生成相應的對象。從實現來看,IOC是把之前在工廠方法裏寫死的對象生成代碼,改變爲由配置文件來定義,也就是把工廠和對象生成這二者獨立分隔開來,目的就是提升靈活性和可維護性。
6 IOC容器的一些產品
    Sun ONE技術體系下的IOC容器有:輕量級的有Spring、Guice、Pico Container、Avalon、HiveMind;重量級的有EJB;不輕不重的有JBoss,Jdon等等。Spring框架做爲Java開發中SSH(Struts、Spring、Hibernate)三劍客之一,大中小項目中都有使用,很是成熟,應用普遍,EJB在關鍵性的工業級項目中也被使用,好比某些電信業務。
    .Net技術體系下的IOC容器有:Spring.Net、Castle等等。Spring.Net是從Java的Spring移植過來的IOC容器,Castle的IOC容器就是Windsor部分。它們均是輕量級的框架,比較成熟,其中Spring.Net已經被逐漸應用於各類項目中。
7 使用IOC框架應該注意什麼
    使用IOC框架產品可以給咱們的開發過程帶來很大的好處,可是也要充分認識引入IOC框架的缺點,作到心中有數,杜絕濫用框架。
    第1、軟件系統中因爲引入了第三方IOC容器,生成對象的步驟變得有些複雜,原本是二者之間的事情,又憑空多出一道手續,因此,咱們在剛開始使用IOC框架的時候,會感受系統變得不太直觀。因此,引入了一個全新的框架,就會增長團隊成員學習和認識的培訓成本,而且在之後的運行維護中,還得讓新加入者具有一樣的知識體系。
    第2、因爲IOC容器生成對象是經過反射方式,在運行效率上有必定的損耗。若是你要追求運行效率的話,就必須對此進行權衡。
    第3、具體到IOC框架產品(好比:Spring)來說,須要進行大量的配製工做,比較繁瑣,對於一些小的項目而言,客觀上也可能加大一些工做成本。
    第4、IOC框架產品自己的成熟度須要進行評估,若是引入一個不成熟的IOC框架產品,那麼會影響到整個項目,因此這也是一個隱性的風險。
    咱們大致能夠得出這樣的結論:一些工做量不大的項目或者產品,不太適合使用IOC框架產品。另外,若是團隊成員的知識能力欠缺,對於IOC框架產品缺少深刻的理解,也不要貿然引入。最後,特別強調運行效率的項目或者產品,也不太適合引入IOC框架產品,象WEB2.0網站就是這種狀況。

 摘自:https://www.cnblogs.com/jhli/p/6019895.html

相關文章
相關標籤/搜索