4

我的应用程序中有一项@Injectable服务作为提供程序添加到AppModule. 我想确保我的开发团队中没有人将它注入任何其他模块。一个实例就足够了,它有一些我不想运行两次的复杂逻辑。有任何想法吗?

我知道 DI 在 Angular 2 中是如何工作的,所以像“确保它仅在 App Module 中作为提供者添加”这样的答案将无济于事。:(

请注意,如果该服务提供给除 AppModule 之外的任何其他服务,我希望它在构建或运行时产生某种错误。

4

1 回答 1

7

Angular 为每个提供者维护一个实例。

确保您只提供一次服务,DI 将确保您的应用程序中只有一个实例。

如果您在一个组件上提供服务@Component({ ..., providers: [...]}),那么实例的数量将与组件实例一样多。

如果您仅在导入到的模块providersAppModule或模块中提供服务,那么整个应用程序将只有一个实例:providersAppModule

@NgModule({
  providers: [...],
  imports: [...]
})
export class AppModule {}

一个陷阱是延迟加载的模块。如果一个模块是延迟加载的,那么那里提供的提供者将导致创建另一个实例,因为延迟加载的模块有自己的 DI 根范围。对于延迟加载的模块,实现forRoot()并添加应该是应用程序范围的单例的提供程序仅在 中forRoot(),而不是在中,providers并将其导入AppModule

@NgModule({
  providers: [...],
  imports: [LazyLoadedModuleWithSingltonProvider.forRoot()]
})
export class AppModule {}

更新

为了防止实例化服务的多个实例,您可以使用类似的解决方法

@Injectable()
export class MyService {
  private static instanceCounter = 0;
  private instanceNumber = instanceCounter++;

  constructor() {
    if(this.instanceNumber > 0) {
      throw 'MyService must be kept a singleton but more than one instance was created';
    }
  }
}

另一种方法是将单例服务移动到 aCoreModule并防止将此模块导入到除AppModule

https://angular.io/docs/ts/latest/guide/ngmodule.html#!#prevent-reimport

只有根 AppModule 应该导入 CoreModule。如果延迟加载的模块导入它,就会发生不好的事情。

于 2017-01-20T14:27:31.830 回答