依賴注入介紹
控制反轉(Inversion of Control厅贪,縮寫為IoC)羞福,是面向對象編程中的一種設計原則幻碱,可以用來減低計算機代碼之間的耦合度答渔。其中最常見的方式叫做依賴注入(Dependency Injection关带,簡稱DI),還有一種方式叫“依賴查找”(Dependency Lookup)沼撕。通過控制反轉宋雏,對象在被創(chuàng)建的時候,由一個調控系統(tǒng)內所有對象的外界實體將其所依賴的對象的引用傳遞給它务豺。也可以說磨总,依賴被注入到對象中。
簡而言之笼沥,?沒事你不要來找我蚪燕,有事我會去找你娶牌。
Angular依賴注入
首先介紹幾個簡單的概念。
1.注入器(Inject):就像制造工廠馆纳,提供了一些列的接口用于創(chuàng)建依賴對象的實例
2.Provider:用于配置注入器诗良,注入器通過它來創(chuàng)建被依賴對象的實例,Provider把標識映射到工廠方法中鲁驶,被依賴的對象就是通過該方法創(chuàng)建的鉴裹。
3.依賴(Dependence):指定了被依賴對象的類型,注入器會根據(jù)此類型創(chuàng)建對應的對象钥弯。
在組件中注入服務
Angular在底層做了大量的初始化工作径荔,這大大簡化了創(chuàng)建依賴注入的過程,在組件中使用依賴注入需要完成以下三個步驟
-通過import導入被依賴對象的服務
-在組建中配置注入器寿羞。在啟動組件時猖凛,Angular會讀取@Component裝飾器里的providers元數(shù)據(jù)赂蠢,它是一個數(shù)組绪穆,配置了該組件需要使用到的所有依賴,Angular的依賴注入框架就會根據(jù)這個列表去創(chuàng)建對應對象的實例虱岂。
-在組件構造函數(shù)中聲明所注入的依賴玖院。注入器就會根據(jù)構造函數(shù)上的聲明,在組件初始化時通過第二步中的providers元數(shù)據(jù)配置依賴第岖,為構造函數(shù)提供對應的依賴服務难菌,最終完成注入過程。
在服務中注入服務
除了組件服務依賴蔑滓,服務間的相互調用也很常見郊酒。
//logger.service.ts
//contact.service.ts
//在組件的providers元數(shù)據(jù)中注冊服務
providers:[LoggerService,ContactService]
在上述中,LoggerService和ContactService這兩個服務都用了@Injectable()裝飾器键袱,實際上它并不是必須的燎窘,只有一個服務依賴其他服務時,才需要用@Injectable()顯示裝飾蹄咖。上述的LoggerService服務并沒有依賴其他服務褐健,它可以不用@Injectable()裝飾,而ContactService服務依賴了其他服務澜汤,則需要@Injectable()裝飾蚜迅。
Angular官方推薦無論是否有依賴其他服務,都應該使用@Injectable()來撞死服務俊抵。一方面谁不,開發(fā)者在給某個組件注入其他服務時,無需再確認該服務是否添加了@Injectable();另一方面徽诲,這也是一種良好的團隊協(xié)作方式拍谐,整個團隊遵循相同的開發(fā)原則烛缔。
在模塊中注入服務
在根組件中注入這個服務,所有子組件都能共享這個服務轩拨。
在模塊中注入服務和之前的注入場景稍有不同践瓷。Angular在啟動程序時會啟動一個根模塊,并加載它所依賴的其他模塊亡蓉,此時會生成一個全局的根注入器晕翠,由該注入器創(chuàng)建的依賴注入對象在整個應用程序級別可見,并共享一個實例砍濒。同時根模塊會指定一個根組件并啟動淋肾,由該根組件添加的依賴注入對象是組件樹級別可見,在根組件以及子組件中共享一個實例爸邢。
層級注入
Angular以組件為基礎樊卓,項目開發(fā)中自然會有層級嵌套的情況,這種組織關系組成了組件樹杠河。根組件下面的各層級的子組件碌尔,可以出現(xiàn)在任何層級的任何組件中,每個組件可以擁有一個或多個依賴對象的注入券敌,每個依賴對象對于注入器而言都是單例唾戚。
//生成唯一標識服務
//子組件A
//子組件B
//父組件
結果將輸出:
Contact-List
ContactA:0.4500488165839276
ContactB:0.5389674473022938
每個子組件都創(chuàng)建了自己獨立的注入器,也就是說通過依賴注入的Random服務都是獨立的待诅,如果把注入器提升到父組件中叹坦,則結果將會不一樣。
此時卑雁,結果變?yōu)?/p>
Contact-List
ContactA:0.6257492668005642
ContactB:0.6257492668005642
上述的輸出結果說明了子組件繼承了父組件的注入器募书,所以子組件使用了相同的Random實例,輸出了相同的結果测蹲。
那么莹捡,該如何選擇在根組件還是在子組件中注入服務呢?
這取決于想讓注入的依賴服務具有局部性還是全局性弛房,由于每個注入器總是將它提供的服務維持單例道盏,因此,如果不需要針對每個組件都提供獨立的服務單例文捶,就可以在根組件中注入荷逞,整個組件樹共享根注入器提供的服務實例;如果需要針對每個組件提供不同的服務實例粹排,就應該在格子組件中配置providers元數(shù)據(jù)來注入服務种远。
Angular如何查找到合適的服務實例呢?
在組件的構造函數(shù)視圖注入某個服務的時候顽耳,Angular會先從當前組件的注入器中查找坠敷,找不到就繼續(xù)往父組件的注入器查找妙同,直到根組件注入器艇劫,最后到應用根注入器懂拾,此時找不到的話就會報錯。