如何在Angular2中正确使用依赖注入(DI)?

时间:2016-03-20 02:20:06

标签: angular angular2-services angular2-di

我一直试图弄清楚(DI)依赖注入如何在Angular2中工作。每当我尝试将服务/或类注入到我的组件中时,我遇到了很多问题/问题。

从不同的谷歌文章中,我需要在组件配置中使用providers: [],或者有时我需要在构造函数中使用@Inject()或直接在bootstrap(app, [service])中注入?我也看到一些文章要我放@injectable装饰。

例如:要注入Http,我只需要import{Http}并将Http放在提供程序中,但对于FormBuilder,我需要在构造函数中使用@Inject()

什么时候使用什么有什么经验法则?你能提供一些示例代码片段吗?谢谢: - )

5 个答案:

答案 0 :(得分:17)

广泛的问题, TL; DR 版本

<强> @Injectable()

  • 是一个装饰器,告诉sudo su - gedit ~/.bashrc export PATH=${PATH}:/your path export PATH=${PATH}:/your path export PATH=${PATH}:/opt/workspace/android/android-sdk-linux/tools export PATH=${PATH}:/opt/workspace/android/android-sdk-linux/platform-tools 装饰类有typescript,并不意味着这个类可以注入其他类。

  • 然后TypeScript了解它需要在构造时使用dependencies依赖项将所需元数据注入到修饰类中。

<强> bootstrap(app, [service])

  • bootstrap()负责在我们的应用程序引导时为其创建根注入器。它将提供者列表作为第二个参数,在创建时将直接传递给注入器。

  • 您使用将在imported等许多地方使用的服务来引导您的应用程序,这也意味着您不需要在类配置中编写Http

<强> providers: [service]

  • 提供商还负责将所有服务的参数传递给providers: [Http]

  • 如果服务提供商不是Injector,则将服务提供给服务提供商。并且仅在少数地方需要。

<强> @Inject()

  • 也是装饰者一个功能,它可以完成实际注入这些服务的工作 像这样。 bootstrap()
  • 但如果您使用TS,那么您需要做的就是constructor(@Inject(NameService) nameService)并且打字稿将处理其余部分。

进一步阅读

希望这会有所帮助。 :)

答案 1 :(得分:13)

Angular2中的依赖注入依赖于链接到组件树的分层注入器。

这意味着您可以在不同级别配置提供商:

  • 引导它时的整个应用程序。在这种情况下,所有子注入器(组件1)将看到此提供程序并共享与之关联的实例。在进行交互时,它将是相同的实例
  • 对于特定组件及其子组件。与之前相同,但对于特定于à的组件。其他组件将不会看到此提供程序。如果重新定义上面定义的内容(例如,引导时),将使用此提供程序。所以你可以覆盖一切。
  • 服务。没有与之关联的提供商。他们使用触发元素中的注入器(直接=组件或间接=触发服务链调用的组件)

关于您的其他问题:

  • @Injectable。要注入一个类,你需要一个装饰器。组件有一个(@Component一个),但服务是简单的类。如果服务需要在其中注入依赖项,则需要此装饰器。
  • @注入。在大多数情况下,构造函数参数的类型足以让Angular2确定要注入的内容。在某些情况下(例如,如果您明确使用OpaqueToken而不是类来注册提供程序),则需要指定有关要注入的内容的一些提示。在这种情况下,您需要使用@Inject。

有关其他详细信息,请参阅以下问题:

答案 2 :(得分:4)

  

我需要使用提供者:[]

要使依赖注入能够为您创建实例,您需要为这些类(或其他值)注册提供者某处

注册提供者的位置决定了创建值的范围。 Angulars DI是分层的。
如果您在树的根目录注册提供程序

<强>&GT; = RC.5

@NgModule({
  providers: [/*providers*/]
  ...
})

或延迟加载的模块

static forRoot(config: UserServiceConfig): ModuleWithProviders {
  return {
    ngModule: CoreModule,
    providers: [
      {provide: UserServiceConfig, useValue: config }
    ]
  };
}

<强>&LT = RC.4

bootstrap(AppComponent, [Providers})@Component(selector: 'app-component', providers: [Providers])(根组件)

然后请求实例的所有组件和服务都获得相同的实例。

如果提供者在其中一个子组件中注册,则为该组件的后代提供新的(不同的)实例。

如果一个组件请求一个实例(通过构造函数参数),DI看起来“向上”组件树(从leaf开始向根),并获取它找到的第一个提供者。如果先前已创建此提供程序的实例,则使用此实例,否则将创建新实例。

  

@注入()

当组件或服务从DI请求值

constructor(someField:SomeType) {}

DI按类型SomeType查找提供商。如果添加了@Inject(SomeType)

constructor(@Inject(SomeType) someField:SomeType) {}

DI通过传递给@Inject()的参数查找提供程序。在上面的示例中,传递给@Inject()的参数与参数的类型相同,因此@Inject(SomeType)是多余的。

但是,在某些情况下,您需要自定义行为,例如注入配置设置。

constructor(@Inject('someName') someField:string) {}

当您注册多个时,类型string不足以区分特定的配置设置 配置值需要在某个地方注册为提供者,如

<强>&GT; = RC.5

@NgModule({
  providers: [{provide: 'someName', useValue: 'abcdefg'})]
  ...
})
export class AppModule {}

<强>&LT = RC.4

bootstrap(AppComponent, [provide('someName', {useValue: 'abcdefg'})])

因此,如果构造函数看起来像<{1}},则@Inject()不需要FormBuilder

constructor(formBuilder: FormBuilder) {}

答案 3 :(得分:2)

我会在其他答案中添加一些我没有看到的内容。 (在我写这篇文章时,这意味着来自Thierry,Günter和A_Singh的答案)。

  • 始终将Injectable()添加到您创建的服务中。虽然只有在您的服务本身需要注入某些内容时才需要它,但最好始终包含它。
  • 指令/组件上的providers数组和NgModules中的providers数组是注册非内置提供程序的唯一两种方法。 (我们不需要注册的内置对象示例包括ElementRefApplicationRef等。我们可以简单地注入这些对象。)
  • 当组件具有providers数组时,该组件将获得Angular注入器。当某些东西想要注入依赖项时(参见构造函数中的指定),会查询注入器。我喜欢将注入器树视为比组件树更好的树。能够满足依赖性请求的第一个注入器就是这样做的。这种注入器层次结构允许依赖关系是单例还是非单例。

答案 4 :(得分:0)

为什么选择@Injectable()?

@Injectable()将一个类标记为可用于实例化的注入器。一般来说,当尝试实例化未标记为@Injectable()的类时,注入器将报告错误。

实际上,我们可能已经从我们的第一个HeroService版本中省略了@Injectable(),因为它没有注入参数。但是我们必须拥有它,因为我们的服务具有注入依赖性。我们需要它,因为Angular需要构造函数参数元数据才能注入Logger。

建议:将@INJECTABLE()添加到每个服务类别 我们建议将@Injectable()添加到每个服务类中,即使是那些没有依赖项的服务类,因此在技术上也不需要它。这就是原因:

面向未来:当我们稍后添加依赖项时,无需记住@Injectable()。

一致性:所有服务都遵循相同的规则,我们不必怀疑为什么缺少装饰器。

Injectors还负责实例化HeroesComponent之类的组件。为什么我们没有将HeroesComponent标记为@Injectable()?

如果我们真的想要,我们可以添加它。这是不必要的,因为HeroesComponent已经用@Component标记,并且这个装饰类(如@Directive和@Pipe,我们稍后会了解)是InjectableMetadata的子类型。它实际上是InjectableMetadata装饰器,它将类标识为注入器实例化的目标。

来源:https://angular.io/docs/ts/latest/guide/dependency-injection.html