1. 程式人生 > >Angular入門-依賴注入

Angular入門-依賴注入

Angular的DI與Java略有不同,主要是在概念方面,從Java轉過來容易被繞暈。記下來備忘。
要理清Angular的DI機制,首先要弄懂Angular中的兩個概念:注入器提供商(提供器)


注入器

在Angular中,每一個元件都會有一個依賴注入器負責注入元件需要的物件例項,一般情況下我們不需要直接呼叫注入器。Angular在初始化元件的時候會從類的建構函式中讀取需要注入的物件並且注入。如:

constructor(private heroSerivce:HeroService){...}

Angular在看到這一行的時候,會去IOC容器中尋找ProductService的例項,並且將其注入到productService物件中。這一點類似於Java中的@Autowired註解所執行的操作。
既然這樣就會出現一個和Java中一樣的問題,如何把一個物件放入到IOC容器中,以及如果有多個例項怎麼選擇注入哪一個。由此引出提供商(提供器)的概念。

提供商

提供商即providers。
通常在component類頭上可以見到這樣的程式碼:

@Component({
  selector: 'app-heroes',
  templateUrl: './app-heros.html',
  styleUrls: ['./app-heros.css'],
  providers: [ HeroService ]
})
export class HeroesComponent {
	constructor(private heroSerivce:HeroService){...}
}

這裡的providers為一個數組,這行程式碼的意思是在當前的元件中註冊一個服務商

HeroService,使得HeroService可以在當前元件中被注入進來。這裡跟Java是有區別的:Angular在這裡把HeroService放到了一個區域性的IOC容器中,該物件僅在當前IOC容器中可以被檢測到並注入。
註冊服務提供商還有另一種寫法,見如下:

import { Injectable } from '@angular/core';
@Injectable({
  providedIn: HeroesComponent,
})
export class HeroService {
  constructor() { }
}

@Injectable裝飾器(等同於Java中的註解)是定義每一個Angular服務所必須的部分,@Injectable標記該服務需要被新增到IOC容器中交由Angular進行管理,與Java中的@Service註解作用是一樣的。
@Injectable裝飾器可以接收一個數據引數providedIn,該引數指定當前service需要給哪一個元件註冊一個提供商,即當前service需要注入到哪一個元件中去

。使用此寫法則無需在@Component中再去宣告providers屬性,因為這二者是完全等價的。


回到剛才服務商的內容中,providers: [ HeroService ]是以下內容的簡寫

providers: [{provide: HeroService, useClass: HeroService}]

第一個欄位provide指定了提供商的token(沒錯就是那個表示令牌的token),第二個欄位useClass說明我要以new的方式建立一個HeroService的例項。token要與constructor中宣告的型別一致。結合上文的constructor來一起看,注入的過程是這樣的:
當注入器發現我需要一個HeroService型別的物件的時候,會去IOC容器中尋找token是HeroService的物件(即provide所指定的型別),如果找到了,則用useClass屬性指定的物件來例項化HeroService並將結果注入到heroService變數中。當然也會有如下可能:

providers: [{provide: HeroService, useClass: AnotherHeroService}]

這種情況下便會new一個AnotherHeroService注入到heroService中。類比Java中子類與父類的關係這裡還是相對容易理解的。
除此之外還可以用工廠方法來返回一個具體的例項,如:

providers: [{provide: HeroService, useFactory: ()=>{......}}]

暫時還沒有使用到,等日後理解再來補充。


如果我想要把一個服務放到全域性IOC容器中該怎麼做,可以這樣寫:

@Injectable({
  providedIn: 'root',
})

root為Angular的根注入器,這樣宣告之後便可以在所有的元件constructor中直接宣告所需要的服務。當然也可以在app.moudle.ts中的providers去宣告,效果是一樣的。