IoC和DI是SPRing的兩個(gè)核心概念,很多人都把它們視為相同的東西,但事實(shí)并非如此。 IoC(Inversion of Control):控制反轉(zhuǎn)。 DI(Dependency Injection):依賴(lài)注入。
為了方便理解,先給出結(jié)論:
控制反轉(zhuǎn)是目的,依賴(lài)注入是實(shí)現(xiàn)控制反轉(zhuǎn)的手段。
控制反轉(zhuǎn)是一種面向?qū)ο蟮乃枷耄且环N寬泛的概念,只要一個(gè)類(lèi)將對(duì)它內(nèi)部狀態(tài)的控制權(quán)交由其他機(jī)制去完成即為『控制反轉(zhuǎn)』。控制反轉(zhuǎn)是為了降低類(lèi)與類(lèi)之間的耦合度。
而Spring采用依賴(lài)注入這一具體的手段來(lái)達(dá)到控制反轉(zhuǎn)的目的。
依賴(lài)注入詳解 一個(gè)類(lèi)內(nèi)部往往有很多成員變量,如:
class A { private Person chaimm;}上述代碼在面向?qū)ο笾锌梢悦枋鰹椋?/p>A類(lèi)和Person類(lèi)之間存在依賴(lài)關(guān)系;A依賴(lài)于Person;A為依賴(lài)類(lèi);Perosn為被依賴(lài)類(lèi);
通常情況下,依賴(lài)類(lèi)需要自己去創(chuàng)建并維護(hù)被依賴(lài)類(lèi)的對(duì)象,如:
class A { private Person chaimm = new Person();}但依賴(lài)注入的做法是:將被依賴(lài)對(duì)象的創(chuàng)建與維護(hù)工作交由專(zhuān)門(mén)的機(jī)構(gòu),而依賴(lài)類(lèi)中只需要聲明所需要的成員變量。 也就是說(shuō),依賴(lài)類(lèi)原本需要主動(dòng)去獲取對(duì)象,但采用依賴(lài)注入后對(duì)象由第三方機(jī)構(gòu)提供,自己僅需聲明需要什么對(duì)象即可。 這樣做的目的就是為了降低兩個(gè)類(lèi)之間的耦合程度。 PS:在Spring中,那個(gè)創(chuàng)建、管理對(duì)象的機(jī)構(gòu)就稱(chēng)為『IoC Service Provider』。
但此時(shí)還沒(méi)體現(xiàn)出依賴(lài)注入能降低耦合度這一點(diǎn),只有當(dāng)依賴(lài)注入與面向接口編程結(jié)合起來(lái),才能真正發(fā)揮依賴(lài)注入的優(yōu)勢(shì)。接下來(lái)先介紹一下『面向接口編程』。
什么是面向接口編程? 一個(gè)類(lèi)依賴(lài)其他類(lèi)的目的是為了獲取其他類(lèi)所提供的服務(wù),可能這種服務(wù)有多種實(shí)現(xiàn),我們可能需要根據(jù)不同的場(chǎng)景使用不同的實(shí)現(xiàn)。此時(shí),我們可以使用多態(tài),將同一功能的多種實(shí)現(xiàn)抽象出一個(gè)接口,并為所有實(shí)現(xiàn)定義一套相同的API。在使用時(shí)聲明接口類(lèi)型的變量而非實(shí)現(xiàn)類(lèi)的變量,并將實(shí)現(xiàn)類(lèi)的對(duì)象賦給接口變量,最后用接口變量去調(diào)用實(shí)現(xiàn)類(lèi)的服務(wù),如:
class A { private Super super = new SuperImpl_1(); public static void main ( String[] args ) { // 使用Super提供的服務(wù) super.method_1(); super.method_2(); super.method_3(); }}這樣,當(dāng)想使用SuperImpl_2提供的功能時(shí),只需替換Super的實(shí)現(xiàn)類(lèi),其他地方不做任何變化:
private Super super = new SuperImpl_2();上述過(guò)程就是面向接口編程的思想:若某一類(lèi)服務(wù)有多種不同的實(shí)現(xiàn),我們需要抽象出一個(gè)接口,并在接口中定義一套API。在使用時(shí)聲明接口類(lèi)型變量,并用實(shí)現(xiàn)類(lèi)的對(duì)象賦值。接下來(lái)通過(guò)接口類(lèi)型的變量調(diào)用服務(wù)即可。當(dāng)功能發(fā)生變化時(shí),僅需替換實(shí)現(xiàn)類(lèi)即可。
在面向接口編程的基礎(chǔ)上使用依賴(lài)注入的好處 上述過(guò)程如果要換一種實(shí)現(xiàn),就必須要修改A類(lèi)的代碼,再重新編譯。而使用了依賴(lài)注入后,由于依賴(lài)類(lèi)不需要自己創(chuàng)建維護(hù)被依賴(lài)對(duì)象,該過(guò)程由IoC Service Provider完成。因此,當(dāng)需要替換實(shí)現(xiàn)類(lèi)時(shí),只需在IoC Service Provider中修改,被依賴(lài)類(lèi)、依賴(lài)類(lèi)都不會(huì)受到影響,此時(shí)這兩個(gè)類(lèi)是松耦合的。
下面介紹三種方式,將被依賴(lài)對(duì)象注入給依賴(lài)類(lèi)。
將被依賴(lài)對(duì)象通過(guò)構(gòu)造函數(shù)的參數(shù)注入給依賴(lài)對(duì)象,并且在初始化對(duì)象的時(shí)候注入。
優(yōu)點(diǎn): 對(duì)象初始化完成后便可獲得可使用的對(duì)象。
缺點(diǎn): 1. 當(dāng)需要注入的對(duì)象很多時(shí),構(gòu)造器參數(shù)列表將會(huì)很長(zhǎng); 2. 不夠靈活。若有多種注入方式,每種方式只需注入指定幾個(gè)依賴(lài),那么就需要提供多個(gè)重載的構(gòu)造函數(shù),麻煩。
IoC Service Provider通過(guò)調(diào)用成員變量提供的setter函數(shù)將被依賴(lài)對(duì)象注入給依賴(lài)類(lèi)。
優(yōu)點(diǎn): 靈活。可以選擇性地注入需要的對(duì)象。
缺點(diǎn): 依賴(lài)對(duì)象初始化完成后由于尚未注入被依賴(lài)對(duì)象,因此還不能使用。
依賴(lài)類(lèi)必須要實(shí)現(xiàn)指定的接口,然后實(shí)現(xiàn)該接口中的一個(gè)函數(shù),該函數(shù)就是用于依賴(lài)注入。該函數(shù)的參數(shù)就是要注入的對(duì)象。 接口注入中,接口的名字、函數(shù)的名字都不重要,只要保證函數(shù)的參數(shù)是要注入的對(duì)象類(lèi)型即可。
缺點(diǎn): 侵入行太強(qiáng),不建議使用。
PS:什么是侵入行? 如果類(lèi)A要使用別人提供的一個(gè)功能,若為了使用這功能,需要在自己的類(lèi)中增加額外的代碼,這就是侵入性。
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注