官术网_书友最值得收藏!

2.1 Spring IoC容器概述

2.1.1 IoC容器和依賴反轉(zhuǎn)模式

子曰:溫故而知新。在這里,我們先簡(jiǎn)要地回顧一下依賴反轉(zhuǎn)的相關(guān)概念。我們選取維基百科中關(guān)于依賴反轉(zhuǎn)的敘述,把這些文字作為我們理解依賴反轉(zhuǎn)這個(gè)概念的參考。這里不會(huì)對(duì)這些原理進(jìn)行學(xué)理上的考究,只是希望提供一些有用的信息,以便給讀者一些啟示。這個(gè)模式非常重要,它是IoC容器得到廣泛應(yīng)用的基礎(chǔ)。

維基百科對(duì)“依賴反轉(zhuǎn)”相關(guān)概念的敘述

早在2004年,Martin Fowler就提出了“哪些方面的控制被反轉(zhuǎn)了?”這個(gè)問題。他得出的結(jié)論是:依賴對(duì)象的獲得被反轉(zhuǎn)了。基于這個(gè)結(jié)論,他為控制反轉(zhuǎn)創(chuàng)造了一個(gè)更好的名字:依賴注入。許多非凡的應(yīng)用(比HelloWorld.java更加優(yōu)美、更加復(fù)雜)都是由兩個(gè)或多個(gè)類通過彼此的合作來實(shí)現(xiàn)業(yè)務(wù)邏輯的,這使得每個(gè)對(duì)象都需要與其合作的對(duì)象(也就是它所依賴的對(duì)象)的引用。如果這個(gè)獲取過程要靠自身實(shí)現(xiàn),那么如你所見,這將導(dǎo)致代碼高度耦合并且難以測(cè)試。

以上的這段話概括了依賴反轉(zhuǎn)的要義,如果合作對(duì)象的引用或依賴關(guān)系的管理由具體對(duì)象來完成,會(huì)導(dǎo)致代碼的高度耦合和可測(cè)試性的降低,這對(duì)復(fù)雜的面向?qū)ο笙到y(tǒng)的設(shè)計(jì)是非常不利的。在面向?qū)ο笙到y(tǒng)中,對(duì)象封裝了數(shù)據(jù)和對(duì)數(shù)據(jù)的處理,對(duì)象的依賴關(guān)系常常體現(xiàn)在對(duì)數(shù)據(jù)和方法的依賴上。這些依賴關(guān)系可以通過把對(duì)象的依賴注入交給框架或IoC容器來完成,這種從具體對(duì)象手中交出控制的做法是非常有價(jià)值的,它可以在解耦代碼的同時(shí)提高代碼的可測(cè)試性。在極限編程中對(duì)單元測(cè)試和重構(gòu)等實(shí)踐的強(qiáng)調(diào)體現(xiàn)了在軟件開發(fā)過程中對(duì)質(zhì)量的承諾,這是軟件項(xiàng)目成功的一個(gè)重要因素。

依賴控制反轉(zhuǎn)的實(shí)現(xiàn)有很多種方式。在Spring中,IoC容器是實(shí)現(xiàn)這個(gè)模式的載體,它可以在對(duì)象生成或初始化時(shí)直接將數(shù)據(jù)注入到對(duì)象中,也可以通過將對(duì)象引用注入到對(duì)象數(shù)據(jù)域中的方式來注入對(duì)方法調(diào)用的依賴。這種依賴注入是可以遞歸的,對(duì)象被逐層注入。就此而言,這種方案有一種完整而簡(jiǎn)潔的美感,它把對(duì)象的依賴關(guān)系有序地建立起來,簡(jiǎn)化了對(duì)象依賴關(guān)系的管理,在很大程度上簡(jiǎn)化了面向?qū)ο笙到y(tǒng)的復(fù)雜性。

關(guān)于如何反轉(zhuǎn)對(duì)依賴的控制,把控制權(quán)從具體業(yè)務(wù)對(duì)象手中轉(zhuǎn)交到平臺(tái)或者框架中,是降低面向?qū)ο笙到y(tǒng)設(shè)計(jì)復(fù)雜性和提高面向?qū)ο笙到y(tǒng)可測(cè)試性的一個(gè)有效的解決方案。它促進(jìn)了IoC設(shè)計(jì)模式的發(fā)展,是IoC容器要解決的核心問題。同時(shí),也是產(chǎn)品化的IoC容器出現(xiàn)的推動(dòng)力。

注意 IoC亦稱為“依賴倒置原理”(Dependency Inversion Principle),幾乎所有框架都使用了倒置注入(Martin Fowler)技巧,是IoC原理的一項(xiàng)應(yīng)用。SmallTalk、C++、Java.NET等面向?qū)ο笳Z言的程序員已使用了這些原理。控制反轉(zhuǎn)是Spring框架的核心。

IoC原理的應(yīng)用在不同的語言中有很多實(shí)現(xiàn),比如SmallTalk、C++、Java等。在同一語言的實(shí)現(xiàn)中也會(huì)有多個(gè)具體的產(chǎn)品,Spring是Java語言實(shí)現(xiàn)中最著名的一個(gè)。同時(shí),IoC也是Spring框架要解決的核心問題。

注意 應(yīng)用控制反轉(zhuǎn)后,當(dāng)對(duì)象被創(chuàng)建時(shí),由一個(gè)調(diào)控系統(tǒng)內(nèi)的所有對(duì)象的外界實(shí)體將其所依賴的對(duì)象的引用傳遞給它,即依賴被注入到對(duì)象中。所以,控制反轉(zhuǎn)是關(guān)于一個(gè)對(duì)象如何獲取它所依賴的對(duì)象的引用,在這里,反轉(zhuǎn)指的是責(zé)任的反轉(zhuǎn)。

我們可以認(rèn)為上面提到的調(diào)控系統(tǒng)是應(yīng)用平臺(tái),或者更具體地說是IoC容器。通過使用IoC容器,對(duì)象依賴關(guān)系的管理被反轉(zhuǎn)了,轉(zhuǎn)到IoC容器中來了,對(duì)象之間的相互依賴關(guān)系由IoC容器進(jìn)行管理,并由Ioc容器完成對(duì)象的注入。這樣就在很大程度上簡(jiǎn)化了應(yīng)用的開發(fā),把應(yīng)用從復(fù)雜的對(duì)象依賴關(guān)系管理中解放出來。簡(jiǎn)單地說,因?yàn)楹芏鄬?duì)象依賴關(guān)系的建立和維護(hù)并不需要和系統(tǒng)運(yùn)行狀態(tài)有很強(qiáng)的關(guān)聯(lián)性,所以可以把在面向?qū)ο缶幊讨行枰獔?zhí)行的諸如新建對(duì)象、為對(duì)象引用賦值等操作交由容器統(tǒng)一完成。這樣一來,這些散落在不同代碼中的功能相同的部分就集中成為容器的一部分,也就是成為面向?qū)ο笙到y(tǒng)的基礎(chǔ)設(shè)施的一部分。

如果對(duì)面向?qū)ο笙到y(tǒng)中的對(duì)象進(jìn)行簡(jiǎn)單分類,會(huì)發(fā)現(xiàn)除了一部分是數(shù)據(jù)對(duì)象外,其他很大一部分對(duì)象是用來處理數(shù)據(jù)的。這些對(duì)象并不常發(fā)生變化,是系統(tǒng)中基礎(chǔ)的部分。在很多情況下,這些對(duì)象在系統(tǒng)中以單件的形式起作用就可以滿足應(yīng)用的需求,而且它們也不常涉及數(shù)據(jù)和狀態(tài)共享的問題。如果涉及數(shù)據(jù)共享方面的問題,需要在這些單件的基礎(chǔ)上再做進(jìn)一步的處理。

同時(shí),這些對(duì)象之間的相互依賴關(guān)系也是比較穩(wěn)定的,一般不會(huì)隨著應(yīng)用的運(yùn)行狀態(tài)的改變而改變。這些特性使這些對(duì)象非常適合由IoC容器來管理,雖然它們存在于應(yīng)用系統(tǒng)中,但是應(yīng)用系統(tǒng)并不承擔(dān)管理這些對(duì)象的責(zé)任,而是通過依賴反轉(zhuǎn)把責(zé)任交給了容器(或者說平臺(tái))。了解了這些背景,Spring IoC容器的原理也就不難理解了。在原理的具體實(shí)現(xiàn)上,Spring有著自己的獨(dú)特思路、實(shí)現(xiàn)技巧和豐富的產(chǎn)品特性。關(guān)于這些原理的實(shí)現(xiàn),下面會(huì)進(jìn)行詳細(xì)的分析。

2.1.2 Spring IoC的應(yīng)用場(chǎng)景

在Java EE企業(yè)應(yīng)用開發(fā)中,前面介紹的IoC(控制反轉(zhuǎn))設(shè)計(jì)模式,是解耦組件之間復(fù)雜關(guān)系的利器,Spring IoC模塊就是這個(gè)模式的一種實(shí)現(xiàn)。在以Spring為代表的輕量級(jí)Java EE開發(fā)風(fēng)行之前,我們更熟悉的是以EJB為代表的開發(fā)模式。在EJB模式中,應(yīng)用開發(fā)人員需要編寫EJB組件,而這種組件需要滿足EJB容器的規(guī)范,才能夠運(yùn)行在EJB容器中,從而獲取事務(wù)管理、生命周期管理這些組件開發(fā)的基本服務(wù)。從獲取的基本服務(wù)上看,Spring提供的服務(wù)和EJB容器提供的服務(wù)并沒有太大的差別,只是在具體怎樣獲取服務(wù)的方式上,兩者的設(shè)計(jì)有很大的不同:在Spring中,Spring IoC提供了一個(gè)基本的JavaBean容器,通過IoC模式管理依賴關(guān)系,并通過依賴注入和AOP切面增強(qiáng)了為JavaBean這樣的POJO對(duì)象賦予事務(wù)管理、生命周期管理等基本功能;而對(duì)于EJB,一個(gè)簡(jiǎn)單的EJB組件需要編寫遠(yuǎn)程/本地接口、Home接口以及Bean的實(shí)現(xiàn)類,而且EJB運(yùn)行是不能脫離EJB容器的,查找其他EJB組件也需要通過諸如JNDI這樣的方式,從而造成了對(duì)EJB容器和技術(shù)規(guī)范的依賴。也就是說Spring把EJB組件還原成了POJO對(duì)象或者JavaBean對(duì)象,降低了應(yīng)用開發(fā)對(duì)傳統(tǒng)J2EE技術(shù)規(guī)范的依賴。

同時(shí),在應(yīng)用開發(fā)中,以應(yīng)用開發(fā)人員的身份設(shè)計(jì)組件時(shí),往往需要引用和調(diào)用其他組件的服務(wù),這種依賴關(guān)系如果固化在組件設(shè)計(jì)中,就會(huì)造成依賴關(guān)系的僵化和維護(hù)難度的增加,這個(gè)時(shí)候,如果使用IoC容器,把資源獲取的方向反轉(zhuǎn),讓IoC容器主動(dòng)管理這些依賴關(guān)系,將這些依賴關(guān)系注入到組件中,那么會(huì)讓這些依賴關(guān)系的適配和管理更加靈活。在具體的注入實(shí)現(xiàn)中,接口注入(Type 1 IoC)、setter注入(Type 2 IoC)、構(gòu)造器注入(Type 3 IoC)是主要的注入方式。在Spring的IoC設(shè)計(jì)中,setter注入和構(gòu)造器注入是主要的注入方式;相對(duì)而言,使用Spring時(shí)setter注入是常見的注入方式,而且為了防止注入異常,Spring IoC容器還提供了對(duì)特定依賴的檢查。

另一方面,在應(yīng)用管理依賴關(guān)系時(shí),可以通過IoC容器將控制進(jìn)行反轉(zhuǎn),在反轉(zhuǎn)的實(shí)現(xiàn)中,如果能通過可讀的文本來完成配置,并且還能通過工具對(duì)這些配置信息進(jìn)行可視化的管理和瀏覽,那么肯定是能夠提高對(duì)組件關(guān)系的管理水平,并且如果耦合關(guān)系需要變動(dòng),并不需要重新修改和編譯Java源代碼,這符合在面向?qū)ο笤O(shè)計(jì)中的開閉準(zhǔn)則,并且能夠提高組件系統(tǒng)設(shè)計(jì)的靈活性,同時(shí),如果結(jié)合OSGi的使用特性,還可以提高應(yīng)用的動(dòng)態(tài)部署能力。

在具體使用Spring IoC容器的時(shí)候,我們可以看到,Spring IoC容器已經(jīng)是一個(gè)產(chǎn)品實(shí)現(xiàn)。作為產(chǎn)品實(shí)現(xiàn),它對(duì)多種應(yīng)用場(chǎng)景的適配是通過Spring設(shè)計(jì)的IoC容器系列來實(shí)現(xiàn)的,比如在某個(gè)容器系列中可以看到各種帶有不同容器特性的實(shí)現(xiàn),可以讀取不同配置信息的各種容器,從不同I/O源讀取配置信息的各種容器設(shè)計(jì),更加面向框架的容器應(yīng)用上下文的容器設(shè)計(jì)等。這些豐富的容器設(shè)計(jì),已經(jīng)可以滿足廣大用戶對(duì)IoC容器的各種使用需求,這時(shí)的Spring IoC容器,已經(jīng)不是原來簡(jiǎn)單的Interface21框架了,已經(jīng)成為一個(gè)IoC容器的工業(yè)級(jí)實(shí)現(xiàn)。下面,我們會(huì)對(duì)IoC容器系列的設(shè)計(jì)和實(shí)現(xiàn)進(jìn)行詳細(xì)分析。

主站蜘蛛池模板: 桐乡市| 来凤县| 云林县| 大田县| 大埔区| 保康县| 西城区| 嘉兴市| 商丘市| 拉萨市| 浙江省| 古田县| 枣阳市| 信阳市| 潍坊市| 阳山县| 宣恩县| 建德市| 张北县| 乌拉特前旗| 淮阳县| 准格尔旗| 尚义县| 青海省| 长宁县| 鄱阳县| 运城市| 福贡县| 商河县| 昌邑市| 华蓥市| 台安县| 南江县| 廊坊市| 枣阳市| 锦屏县| 密云县| 万全县| 朝阳县| 蒙阴县| 刚察县|