Angular依賴注入介紹

? ? ? ?依賴注入(DI -- Dependency Injection)是一種重要的應(yīng)用設(shè)計模式溪北。Angular里面也有自己的DI框架看峻,在設(shè)計應(yīng)用時經(jīng)常會用到它佳遂,它可以我們的開發(fā)效率和模塊化程度。

? ? ? ?依賴荒适,是當(dāng)類需要執(zhí)行其功能時慢显,所需要的服務(wù)或?qū)ο笞δ!I是一種編碼模式,其中的類會從外部源中請求獲取依賴荚藻,而不需要我們自己創(chuàng)建它們屋灌。

? ? ? ?Angular系統(tǒng)中通過在類上添加@Injectable裝飾器來告訴系統(tǒng)這個類(服務(wù))是可注入的。當(dāng)然了這僅僅只是告訴Angular系統(tǒng)這個類(服務(wù))類是可注入的应狱。但是這個服務(wù)可以在哪里使用共郭,由誰提供,就得靠注入器和提供商來一起確定了疾呻。

  • 注入器: 注入器負(fù)責(zé)服務(wù)實(shí)例的創(chuàng)建除嘹,并把它們注入到你想要注入的類中。從而確定服務(wù)的使用范圍和服務(wù)的生命周期岸蜗。

  • 提供商: 服務(wù)由誰提供憾赁。Angular本身沒法自動判斷你是打算自行創(chuàng)建服務(wù)類的實(shí)例,還是等注入器來創(chuàng)建它散吵。如果想通過注入器來創(chuàng)建龙考,必須在每個注入器里面為每個服務(wù)指定服務(wù)提供商蟆肆。

一 注入器(Injector)

? ? ? ?Angular依賴注入中的注入器(Injector),用來管理服務(wù)晦款。包括服務(wù)的創(chuàng)建炎功,服務(wù)的獲取。

? ? ? ?Angular依賴注入系統(tǒng)中的注入器(Injector)是多級的缓溅。實(shí)際上蛇损,應(yīng)用程序中有一個與組件樹平行的注入器樹。你可以在組件樹中的任何級別上重新配置注入器坛怪,注入提供商淤齐。

? ? ? ?還有一點(diǎn)要特別注意,Angular注入器是冒泡機(jī)制的袜匿。當(dāng)一個組件申請獲得一個依賴時更啄,Angular先嘗試用該組件自己的注入器來滿足它居灯。如果該組件的注入器沒有找到對應(yīng)的提供商祭务,它就把這個申請轉(zhuǎn)給它父組件的注入器來處理。如果當(dāng)前注入器也無法滿足這個申請怪嫌,它就繼續(xù)轉(zhuǎn)給它在注入器樹中的父注入器义锥。這個申請繼續(xù)往上冒泡—直到Angular找到一個能處理此申請的注入器或者超出了組件樹中的祖先位置為止。如果超出了組件樹中的祖先還未找到岩灭,Angular就會拋出一個錯誤拌倍。

所有所有的一切最終都是服務(wù)組件的。每個組件的注入器其實(shí)包含兩部分:組件本身注入器的噪径,組件所在NgMoudle對應(yīng)的注入器柱恤。

? ? ? ?在我們的Angular系統(tǒng)中我們可以認(rèn)為NgModule是一個注入器,Component也是一個注入器熄云。

1.1 NgMoudle(模塊)級注入器

? ? ? ?NgMoudle(模塊)級注入器會告訴Angualr系統(tǒng)把服務(wù)作用在NgModule上。這個服務(wù)器可以在這個NgModule范圍下所有的組件上使用妙真。NgModule級注入服務(wù)有兩種方式:一個是在 @NgModule()的providers元數(shù)據(jù)中指定缴允、另一種是直接在@Injectable()的providedIn選項(xiàng)中指定模塊類。

? ? ? ?NgMoudle級注入器兩種方式:@NgModule() providers 元數(shù)據(jù)中指定珍德、或者直接在@Injectable() 的 providedIn 選項(xiàng)中指定某個模塊類练般。

1.1.1 通過@NgModule()的providers將服務(wù)注入到NgModule中

? ? ? ?通過@NgModule()的providers將服務(wù)注入到NgModule中,限制服務(wù)只能在當(dāng)前NgModule里面使用锈候。

export interface NgModule {
  ...
  
  /**
   * 本模塊需要創(chuàng)建的服務(wù)薄料。這些服務(wù)可以在本模塊的任何地方使用。
   * NgModule我們可以認(rèn)為是注入器泵琳,Provider是提供商摄职。注入器通過提供商的信息來創(chuàng)建服務(wù)
   */
  providers?: Provider[];
  
  ...
}

關(guān)于Provider(提供商)更加具體的用戶我們會在下文做詳細(xì)的解釋誊役。

? ? ? ?比如如下的代碼我們先定義一個NgmoduleProvidersService服務(wù)類。當(dāng)前類只是添加了@Injectable()告訴Angular系統(tǒng)這是一個可注入的服務(wù)谷市。

import {Injectable} from '@angular/core';

/**
 * 我們將在NgmoduleProvidersModule中注入該服務(wù)蛔垢。
 * 然后在NgmoduleProvidersComponent里面使用該服務(wù)
 */
@Injectable()
export class NgmoduleProvidersService {

    constructor() {
    }

    // TODO:其他邏輯
}

? ? ? ?接下來,想在NgmoduleProvidersModule模塊里面所有的地方使用該服務(wù)迫悠。很簡單鹏漆,我們在@NgModule元數(shù)據(jù)providers里面指定這個類NgmoduleProvidersService就好了。(該服務(wù)的TOKEN是NgmoduleProvidersService创泄,提供商也是他自己艺玲。關(guān)于提供商更加具體的用法,我們會在下文詳細(xì)講解)

import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {NgmoduleProvidersComponent} from './ngmodule-providers.component';
import {NgmoduleProvidersRoutingModule} from './ngmodule-providers-routing.module';
import {NgmoduleProvidersService} from './ngmodule-providers.service';

@NgModule({
    declarations: [
        NgmoduleProvidersComponent
    ],
    providers: [
        NgmoduleProvidersService,
    ],
    imports: [
        CommonModule,
        NgmoduleProvidersRoutingModule
    ]
})
export class NgmoduleProvidersModule {
}

1.1.2 通過@Injectable()的providedIn將服務(wù)注入到NgModule中

? ? ? ?@Injectable()裝飾器里面的元數(shù)據(jù)providedIn也可以直接指定NgModue鞠抑。來告知服務(wù)可以在哪里使用饭聚。providedIn的值可以有三種:一種是Type<any>也是NgModule、一種是字符串'root'碍拆、一種是null若治。

export interface InjectableDecorator {
    /**
     * providedIn有三種值:Type<any>、 ‘root’感混、 null
     * Type<any>指的是NgModule
     */
    (): TypeDecorator;
    (options?: {
        providedIn: Type<any> | 'root' | null;
    } & InjectableProvider): TypeDecorator;
    new (): Injectable;
    new (options?: {
        providedIn: Type<any> | 'root' | null;
    } & InjectableProvider): Injectable;
}

當(dāng)providedIn是null的時候端幼。咱們僅僅是告訴了系統(tǒng)這個類是可注入的。在其他的地方還使用不了弧满。如果想使用需要在NgModule裝飾器或者Component裝飾器里面的元數(shù)據(jù)providers中指定婆跑。

1.1.2.1 providedIn: 'root'

? ? ? ?providedIn: 'root'。咱們可以簡單的認(rèn)為root字符串就代表頂級AppModule庭呜。表明當(dāng)前服務(wù)可以在整個Angular應(yīng)用里面使用滑进。而且在整個Angular應(yīng)用中只有一個服務(wù)實(shí)例。

? ? ? ?比如如下的代碼我們定義一個StartupService服務(wù)類募谎。 providedIn: 'root'扶关。則
StartupService這個類當(dāng)前項(xiàng)目的任務(wù)地方注入使用。而且都是同一份實(shí)例對象数冬。

import {Injectable} from '@angular/core';

/**
 * StartupService可以在系統(tǒng)的任務(wù)地方使用
 */
@Injectable({
    providedIn: 'root'
})
export class StartupService {

    constructor() {
    }

    // TODO: 其他邏輯
}

1.1.2.2 providedIn: NgModule

? ? ? ?providedIn: NgModule节槐。通過providedIn直接指定一個NgModule。讓當(dāng)前服務(wù)只能在這個指定的NgModule里面使用拐纱。

? ? ? ?而且providedIn: NgModule這種情況是可以搖樹優(yōu)化铜异。只要在服務(wù)本身的 @Injectable() 裝飾器中指定提供商,而不是在依賴該服務(wù)的NgModule或組件的元數(shù)據(jù)中指定秸架,你就可以制作一個可搖樹優(yōu)化的提供商揍庄。當(dāng)前前提是這個NgModule是懶加載的。

搖樹優(yōu)化是指一個編譯器選項(xiàng)东抹,意思是把應(yīng)用中未引用過的代碼從最終生成的包中移除蚂子。如果提供商是可搖樹優(yōu)化的沃测,Angular編譯器就會從最終的輸出內(nèi)容中移除應(yīng)用代碼中從未用過的服務(wù)。 這會顯著減小你的打包體積缆镣。

? ? ? ?providedIn: NgModule使用的時候有一個特別要特別注意的地方芽突。舉個例子比如我們想在NgmoduleProvidersModule模塊中使用NgmoduleProviderInModuleService服務(wù)。如下的寫法是不對的董瞻。

import { Injectable } from '@angular/core';
import {NgmoduleProvidersModule} from './ngmodule-providers.module';

@Injectable({
  providedIn: NgmoduleProvidersModule
})
export class NgmoduleProviderInModuleService {

  constructor() { }
}

編譯的時候會拋出一個警告信息寞蚌,編譯不過。

WARNING in Circular dependency detected:

? ? ? ?為了解決這個異常信息钠糊,讓代碼能正常編譯挟秤,我們需要借助一個NgModule(NgmoduleProvidersResolveModule名字你隨便來)來過渡下。這個過渡NgModule賦值給providedIn抄伍。最后在我們真正想使用該服務(wù)的NgModule里面imports這個過渡NgModule艘刚。說的有點(diǎn)繞來繞去的。我們直接用代碼來說明截珍。

// 需要在模塊NgmoduleProvidersModule里面使用的服務(wù)NgmoduleProviderInModuleService

import {Injectable} from '@angular/core';
import {NgmoduleProvidersResolveModule} from './ngmodule-providers-resolve.module';

/**
 * providedIn中直接指定了當(dāng)前服務(wù)可以在哪個模塊使用
 * 特別說明:我們想在NgmoduleProvidersModule模塊里面使用該服務(wù)攀甚,
 * 如果providedIn直接寫NgmoduleProvidersModule,會報編譯錯誤岗喉,
 * 所以我們定義了一個中間模塊NgmoduleProvidersResolveModule秋度,
 * 然后在NgmoduleProvidersModule里面引入了NgmoduleProvidersResolveModule。
 *
 * NgmoduleProvidersResolveModule相當(dāng)于一個過渡的作用
 */
@Injectable({
    providedIn: NgmoduleProvidersResolveModule
})
export class NgmoduleProviderInModuleService {

    constructor() {
    }

    // TODO: 其他邏輯
}


// 過渡NgModule NgmoduleProvidersResolveModule

import {NgModule} from '@angular/core';

/**
 * providedIn: NgModule的時候NgModule不能直接寫對應(yīng)的NgModule,
 * 需要一個過渡的NgModule钱床。否則編譯報錯:WARNING in Circular dependency detected
 */
@NgModule({
})
export class NgmoduleProvidersResolveModule {
}



// NgmoduleProvidersModule 服務(wù)將在該模塊里面使用荚斯。

import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {NgmoduleProvidersComponent} from './ngmodule-providers.component';
import {NgmoduleProvidersRoutingModule} from './ngmodule-providers-routing.module';
import {NgmoduleProvidersService} from './ngmodule-providers.service';
import {NgmoduleProvidersResolveModule} from './ngmodule-providers-resolve.module';


@NgModule({
    declarations: [
        NgmoduleProvidersComponent
    ],
    providers: [
        NgmoduleProvidersService,
    ],
    imports: [
        CommonModule,
        /**
         * 導(dǎo)入了過渡的NgModule
         */
        NgmoduleProvidersResolveModule,
        NgmoduleProvidersRoutingModule
    ]
})
export class NgmoduleProvidersModule {
}

1.2 Component(組件)級注入器

? ? ? ?組件級注入器,每個組件也是一個注入器查牌。通過在組件級注入器中注入服務(wù)事期。這樣該組件實(shí)例或其下級組件實(shí)例都可以使用這個服務(wù)(當(dāng)然我們也可以設(shè)置只在當(dāng)前組件使用,子組件不能使用纸颜。這個就涉及到viewProviders和providers的區(qū)別了)兽泣。組件注入器提供的服務(wù)具有受限的生命周期。該組件的每個新實(shí)例都會獲得自己的一份服務(wù)實(shí)例胁孙。當(dāng)銷毀組件實(shí)例時唠倦,服務(wù)實(shí)例也會被同時銷毀。所以組件級別的服務(wù)和組件是綁定在一起的浊洞。一起創(chuàng)建一起消失牵敷。

? ? ? ?我們通過一個簡單的實(shí)例來看看組件級注入器的使用胡岔。

首先定義一個ComponentInjectService服務(wù)法希。

import { Injectable } from '@angular/core';

/**
 * 當(dāng)前服務(wù)在組件里面使用,會在需要使用的組件里面注入
 */
@Injectable()
export class ComponentInjectService {

  constructor() { }
}

然后在組件里面注入

import {ComponentInjectService} from './component-inject.service';

@Component({
    selector: 'app-ngmodule-providers',
    templateUrl: './ngmodule-providers.component.html',
    styleUrls: ['./ngmodule-providers.component.less'],
    providers: [ComponentInjectService],   // providers提供的服務(wù)在當(dāng)前組件和子組件都可以使用
    // viewProviders: [ComponentInjectService], // viewProviders提供的服務(wù)在當(dāng)前組件使用
})
export class NgmoduleProvidersComponent implements OnInit {
    
    constructor(private service: ComponentInjectService) {
    }

    ngOnInit() {
    }

}

二靶瘸,提供商(Provider)

? ? ? ?上面所有的實(shí)例代碼苫亦,咱們往注入器里面注入服務(wù)的時候毛肋,使用的是最簡單的一種方式TypeProvider,也是咱們用的最多的一種方式屋剑。不管是@NgModule裝飾器里面還是@Component裝飾器里面润匙。providers元數(shù)據(jù)里面都是直接寫了服務(wù)類。類似如下的代碼唉匾。

@NgModule({
    ...
    providers: [
        NgmoduleProvidersService,
    ],
    ...
})

上面代碼中的providers對象是一個Provider(提供商)數(shù)組(當(dāng)前注入器需要注入的依賴對象)孕讳,在注入器中注入服務(wù)時咱們還必須指定這些提供商,否則注入器就不知道怎么來創(chuàng)建此服務(wù)巍膘。Angular系統(tǒng)中我們通過Provider來描述與Token相關(guān)聯(lián)的依賴對象的創(chuàng)建方式厂财。

? ? ??簡而言之Provider是用來描述與Token關(guān)聯(lián)的依賴對象的創(chuàng)建方式。當(dāng)我們使用Token向DI系統(tǒng)獲取與之相關(guān)連的依賴對象時峡懈,DI 會根據(jù)已設(shè)置的創(chuàng)建方式璃饱,自動的創(chuàng)建依賴對象并返回給使用者。中間過程我們不需要過肪康。我們只需要知道哪個Token對應(yīng)哪個(或者哪些)服務(wù)就好了荚恶。通過Token來獲取到對應(yīng)的服務(wù)。所以關(guān)于Povider我們重點(diǎn)需要知道以下兩個東西:Token,Token對應(yīng)對象的創(chuàng)建方式磷支。

2.1 Povider Token

? ? ??Token的作用是用來標(biāo)識依賴對象的谒撼,Token值可以是Type、InjectionToken齐唆、OpaqueToken類的實(shí)例或字符串嗤栓。通常不推薦使用字符串,因?yàn)槿绻褂米址嬖诿麤_突的可能性比較高箍邮。

你可以簡單的認(rèn)為Token是依賴對象的key茉帅。在我們需要使用依賴對象的時候我們可以通過這個key找到依賴對象。

2.2 對象的創(chuàng)建方式

? ? ??給出了依賴對象的創(chuàng)建方式锭弊,注入器才能知道怎么去創(chuàng)建對象堪澎。Provider有如下幾種方式:TypeProvider ,ValueProvider味滞,ClassProvider樱蛤,ConstructorProvider, ExistingProvider剑鞍,F(xiàn)actoryProvider昨凡,any[]。

export declare type Provider = TypeProvider | ValueProvider | ClassProvider | ConstructorProvider | ExistingProvider | FactoryProvider | any[];

ConstructorProvider這種方式蚁署,咱們就不考慮了便脊,我是在是沒找到這種方式的使用場景。

2.2.1 TypeProvider

export interface TypeProvider extends Type<any> {
}

? ? ??TypeProvider用于告訴Injector(注入器)光戈,使用給定的Type創(chuàng)建對象哪痰,并且Token也是給定的Type遂赠。這也是我們用的最多的一種方式。比如如下晌杰。就是采用的TypeProvider方式跷睦。

@NgModule({
  ...
  providers: [NgmoduleProvidersService], // NgmoduleProvidersService是我們定義的服務(wù),TypeProvider方式
})

2.2.2 ClassProvider

? ? ??ClassProvider用于告訴Injector(注入器)肋演,useClass指定的Type創(chuàng)建的對應(yīng)對象就是Token對應(yīng)的對象抑诸。

export interface ClassSansProvider {
    /**
     * token生成對象對應(yīng)的class.
     * 用該class生成服務(wù)對象
     */
    useClass: Type<any>;
}

export interface ClassProvider extends ClassSansProvider {
    /**
     * 用于設(shè)置與依賴對象關(guān)聯(lián)的Token值,Token值可能是Type爹殊、InjectionToken哼鬓、OpaqueToken的實(shí)例或字符串
     */
    provide: any;
    /**
     * 用于標(biāo)識是否multiple providers,若是multiple類型边灭,則返回與Token關(guān)聯(lián)的依賴對象列表
     * 簡單來說如果multi是true的話异希,通過provide(Token)獲取的依賴對象是一個列表。
     * 同一個Token可以注入多個服務(wù)
     */
    multi?: boolean;
}

? ? ??簡單使用

export const TOKEN_MODULE_CLASS_PROVIDER = new InjectionToken<any>('TOKEN_MODULE_CLASS_PROVIDER');
// ModuleClassProviderService類是我們依賴對象

@NgModule({
    ...
    providers: [
        {
            provide: TOKEN_MODULE_CLASS_PROVIDER, useClass: ModuleClassProviderService
        }
    ],
    ...
})
export class ClassProviderModule {
}

2.2.3 ValueProvider

? ? ??ValueProvider用于告訴Injector(注入器)绒瘦,useValue指定的值(可以是具體的對象也可以是string ,number等等之類的值)就是Token依賴的對象称簿。

export interface ValueSansProvider {
  /**
   * 需要注入的值
   */
  useValue: any;
}

export interface ValueProvider extends ValueSansProvider {
  /**
   * 用于設(shè)置與依賴對象關(guān)聯(lián)的Token值,Token值可能是Type惰帽、InjectionToken憨降、OpaqueToken的實(shí)例或字符串
   */
  provide: any;
  /**
   * 用于標(biāo)識是否multiple providers,若是multiple類型该酗,則返回與Token關(guān)聯(lián)的依賴對象列表
   * 簡單來說如果multi是true的話授药,通過provide(Token)獲取的依賴對象是一個列表。
   * 同一個Token可以注入多個服務(wù)
   */
  multi?: boolean;
}

? ? ??簡單實(shí)例呜魄。

export const TOKEN_MODULE_CONFIG = new InjectionToken<Config>('TOKEN_MODULE_CONFIG');

/**
 * Config是我們自定義的一個配置對象
 */
const config = new Config();
config.version = '1.1.2';

@NgModule({
    ...
    providers: [
        {provide: TOKEN_MODULE_CONFIG, useValue: config},
    ],
    ...
})
export class ValueProviderModule {
}

2.2.4 FactoryProvider

? ? ??FactoryProvider 用于告訴 Injector (注入器)悔叽,通過調(diào)用 useFactory對應(yīng)的函數(shù),返回Token對應(yīng)的依賴對象爵嗅。

export interface FactorySansProvider {
  /**
   * 用于創(chuàng)建對象的工廠函數(shù)
   */
  useFactory: Function;
  /**
   * 依賴對象列表(你也可以簡單的認(rèn)為是創(chuàng)建對象構(gòu)造函數(shù)里面需要的依賴對象)
   */
  deps?: any[];
}

export interface FactoryProvider extends FactorySansProvider {
  /**
   * 用于設(shè)置與依賴對象關(guān)聯(lián)的Token值娇澎,Token值可能是Type、InjectionToken睹晒、OpaqueToken的實(shí)例或字符串
   */
  provide: any;
  /**
   * 用于標(biāo)識是否multiple providers趟庄,若是multiple類型,則返回與Token關(guān)聯(lián)的依賴對象列表
   * 簡單來說如果multi是true的話伪很,通過provide(Token)獲取的依賴對象是一個列表戚啥。
   * 同一個Token可以注入多個服務(wù)
   */
  multi?: boolean;
}

? ? ??useFactory對應(yīng)一個函數(shù),該函數(shù)需要的對象通過deps提供锉试,deps是一個Token數(shù)組猫十。

// TOKEN
export const TOKEN_FACTORY_MODULE_DEPS = new InjectionToken<ModuleFactoryProviderService>('TOKEN_FACTORY_MODULE_DEPS');
export const TOKEN_FACTORY_MODULE = new InjectionToken<ModuleFactoryProviderService>('TOKEN_FACTORY_MODULE');


/**
 * 創(chuàng)建ModuleFactoryProviderService對象,
 * 該對象依賴另一個服務(wù),通過deps提供
 */
function moduleServiceFactory(initValue) {
    return new ModuleFactoryProviderService(initValue);
}

@NgModule({
    ...
    providers: [
        { // 創(chuàng)建TOKEN_FACTORY_MODULE對應(yīng)的服務(wù)時候炫彩,需要依賴的值
            provide: TOKEN_FACTORY_MODULE_DEPS,
            useValue: 'initValue'
        },
        {
            provide: TOKEN_FACTORY_MODULE,
            useFactory: moduleServiceFactory,
            deps: [TOKEN_FACTORY_MODULE_DEPS]
        }
    ],
    ...
})
export class FactoryProviderModule {
}

2.2.5 ExistingProvider

? ? ??ExistingProvider用于告訴Injector(注入器),想獲取Token(provide)對應(yīng)的對象的時候絮短,使用useExisting(Token)對應(yīng)的對象江兢。

一定要記住useExisting對應(yīng)的值也是一個Token。

export interface ExistingSansProvider {
  /**
   * 已經(jīng)存在的 `token`  (等價于 `injector.get(useExisting)`)
   */
  useExisting: any;
}

export interface ExistingProvider extends ExistingSansProvider {
  /**
   * 用于設(shè)置與依賴對象關(guān)聯(lián)的Token值丁频,Token值可能是Type杉允、InjectionToken、OpaqueToken的實(shí)例或字符串
   */
  provide: Type<any>;
  /**
   * 用于標(biāo)識是否multiple providers席里,若是multiple類型叔磷,則返回與Token關(guān)聯(lián)的依賴對象列表
   * 簡單來說如果multi是true的話,通過provide(Token)獲取的依賴對象是一個列表奖磁。
   * 同一個Token可以注入多個服務(wù)
   */
  multi?: boolean;
}

? ? ??實(shí)例代碼改基。

@NgModule({
    ...
    providers: [
        ModuleExistingProviderServiceExtended, // 我們先通過TypeProvider的方式注入了ModuleExistingProviderServiceExtended
        {provide: ModuleExistingProviderService, useExisting: ModuleExistingProviderServiceExtended}
    ],
    ...
})
export class ExistingProviderModule {
}

三,獲取依賴對象

? ? ??通過上面的講解咖为,我們已經(jīng)知道怎么的在指定的注入器里面通過提供商注入相應(yīng)的依賴對象秕狰。如果我們想在指定的地方(一般是組件里面)使用依賴對象,就得先拿到對象躁染。接下來我們就得叨叨怎么拿到這個對象了鸣哀。

? ? ??通過提供者(providers)注入服務(wù)的時候,每個服務(wù)我們都給定了Token(Provider里面的provide對象對應(yīng)的值)吞彤。TypeProvider例外我衬,其實(shí)TypeProvider雖然沒有明確的指出Token。其實(shí)內(nèi)部的處理饰恕,Token就是TypeProvider設(shè)置的Type挠羔。

? ? ??我們總結(jié)出獲取依賴對象有三種方式:

3.1 構(gòu)造函數(shù)中通過@Inject獲取

? ? ??借助@Inject裝飾器獲取到指定的依賴對象。@Inject的參數(shù)就是需要獲取的依賴對象對應(yīng)的Token埋嵌。

    /**
     * 通過@Inject裝飾器獲取Token對應(yīng)依賴的對象
     */
    constructor(@Inject(TOKEN_MODULE_CLASS_PROVIDER) private service: ModuleClassProviderService) {
    }

3.2 通過Injector.get(Token)獲取

? ? ??先在構(gòu)造函數(shù)中把Injector對象注入進(jìn)來褥赊,然后在通過Injector.get(Token)獲取對象。同樣參數(shù)也是依賴對象對應(yīng)的Token莉恼。

    service: ModuleClassProviderService;

    /**
     * 借助Injector服務(wù)來獲取Token對應(yīng)的服務(wù)
     */
    constructor(private injector: Injector) {
       this.service = injector.get(TOKEN_MODULE_CLASS_PROVIDER);
    }

3.3 構(gòu)造函數(shù)中通過Type獲取

? ? ??直接在構(gòu)造函數(shù)中通過Type來獲取拌喉,這種獲取方式有個前提。必須是TypeProvider方式提供的服務(wù)俐银。

    constructor(private service: ModuleClassProviderService) {
    }

四尿背,Provider中的multi

? ? ??上面講提供商(Provider)的時候多次出現(xiàn)了multi。multi表示同一個Token對應(yīng)的服務(wù)可以是多個捶惜。當(dāng)使用multi的時候田藐。通過Token獲取依賴服務(wù)的時候是一個服務(wù)數(shù)組。其實(shí)也很好理解。比如網(wǎng)絡(luò)攔截器汽久。是允許同一個Token有多個服務(wù)鹤竭。每個攔截器做不同的邏輯處理。


? ? ??文章最后給出文章涉及到的實(shí)例代碼下載地址https://github.com/tuacy/angular-inject景醇,同時我們對Angular依賴注入的使用做一個簡單的總結(jié)臀稚。Angular里面使用依賴注入步驟:

  • 1.定義依賴對象的業(yè)務(wù)邏輯。

就是定義依賴對象服務(wù)類三痰,確定服務(wù)類需要干哪些事情吧寺。

  • 2.明確我們依賴對象的作用范圍。

確定注入器散劫,是用NgModule注入器呢稚机,實(shí)時Component注入器。

  • 3.依賴對象的Token確定获搏。

依賴對象的獲取都是通過Token去獲取的赖条。

  • 4.依賴對象提供商的確定。

Provider用那種方式常熙,TypeProvider呢谋币,還是ValueProvider呢等等。

  • 5.在需要使用依賴對象的地方獲取到依賴對象症概。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蕾额,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子彼城,更是在濱河造成了極大的恐慌诅蝶,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,692評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件募壕,死亡現(xiàn)場離奇詭異调炬,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)舱馅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,482評論 3 392
  • 文/潘曉璐 我一進(jìn)店門缰泡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人代嗤,你說我怎么就攤上這事棘钞。” “怎么了干毅?”我有些...
    開封第一講書人閱讀 162,995評論 0 353
  • 文/不壞的土叔 我叫張陵宜猜,是天一觀的道長。 經(jīng)常有香客問我硝逢,道長姨拥,這世上最難降的妖魔是什么绅喉? 我笑而不...
    開封第一講書人閱讀 58,223評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮叫乌,結(jié)果婚禮上柴罐,老公的妹妹穿的比我還像新娘。我一直安慰自己憨奸,他們只是感情好革屠,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,245評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著膀藐,像睡著了一般。 火紅的嫁衣襯著肌膚如雪红省。 梳的紋絲不亂的頭發(fā)上额各,一...
    開封第一講書人閱讀 51,208評論 1 299
  • 那天,我揣著相機(jī)與錄音吧恃,去河邊找鬼虾啦。 笑死,一個胖子當(dāng)著我的面吹牛痕寓,可吹牛的內(nèi)容都是我干的傲醉。 我是一名探鬼主播,決...
    沈念sama閱讀 40,091評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼呻率,長吁一口氣:“原來是場噩夢啊……” “哼硬毕!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起礼仗,我...
    開封第一講書人閱讀 38,929評論 0 274
  • 序言:老撾萬榮一對情侶失蹤吐咳,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后元践,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體韭脊,經(jīng)...
    沈念sama閱讀 45,346評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,570評論 2 333
  • 正文 我和宋清朗相戀三年单旁,在試婚紗的時候發(fā)現(xiàn)自己被綠了沪羔。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,739評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡象浑,死狀恐怖蔫饰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情愉豺,我是刑警寧澤死嗦,帶...
    沈念sama閱讀 35,437評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站粒氧,受9級特大地震影響越除,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,037評論 3 326
  • 文/蒙蒙 一摘盆、第九天 我趴在偏房一處隱蔽的房頂上張望翼雀。 院中可真熱鬧,春花似錦孩擂、人聲如沸狼渊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,677評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽狈邑。三九已至,卻和暖如春蚤认,著一層夾襖步出監(jiān)牢的瞬間米苹,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,833評論 1 269
  • 我被黑心中介騙來泰國打工砰琢, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蘸嘶,地道東北人。 一個月前我還...
    沈念sama閱讀 47,760評論 2 369
  • 正文 我出身青樓陪汽,卻偏偏與公主長得像训唱,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子挚冤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,647評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 一况增、什么是依賴注入 控制反轉(zhuǎn)(IoC) 控制反轉(zhuǎn)的概念最早在2004年由Martin Fowler提出,是針對面向...
    Keriy閱讀 3,179評論 0 8
  • 本文作為學(xué)習(xí)的感悟記錄训挡,閱讀本文之前需要熟讀相關(guān)的官方文檔巡通。 declearable(components, di...
    csRyan閱讀 1,398評論 0 1
  • 一、什么是依賴注入 控制反轉(zhuǎn) Inversion of Control (簡稱IOC) 最早在2004年由Mart...
    笨蛋小明閱讀 3,137評論 3 6
  • 1.背景介紹 以前原始社會舍哄,我們需要斧子宴凉,然后由于還沒有社會分工,只能自己打磨一把來使用表悬,對應(yīng)在程序上是我們需要一...
    LMmx閱讀 345評論 0 2
  • Angular算是將后端開發(fā)工程化引入前端的先驅(qū)之一,而Dependency injection依賴注入(后面簡稱...
    點(diǎn)融黑幫閱讀 2,252評論 0 5