获取没有构造函数注入的服务实例

我在引导程序中定义了一个 @Injectable服务。我希望在不使用构造函数注入的情况下获取服务的实例。我尝试使用 ReflectiveInjector.resolveAndCreate,但它似乎创建了一个新的实例。

我尝试这样做的原因是,我有一个由许多组件派生的基本组件。现在我需要访问一个服务,但是我不想把它添加到构造函数中,因为我不想把服务注入到所有的派生组件中。

TLDR: I need a ServiceLocator.GetInstance<T>()

更新: RC5 + 的更新代码: < a href = “ https://stackoverflow. com/questions/39409328/store-injector-instance-for-use-in-Component”> 存储组件中使用的注入器实例

117786 次浏览

是的,ReflectiveInjector.resolveAndCreate()创建一个新的未连接的注入器实例。

您可以注入 Angulars Injector实例,并从它获得所需的实例使用

constructor(private injector:Injector) {
injector.get(MyService);
}

您还可以将 Injector存储在某个全局变量中,然后使用这个注入器实例获取所提供的实例,例如,如 https://github.com/angular/angular/issues/4112#issuecomment-153811572所述

另一种方法是定义一个自定义装饰器(一个设置依赖注入元数据的 CustomInjectable:

export function CustomComponent(annotation: any) {
return function (target: Function) {


// DI configuration
var parentTarget = Object.getPrototypeOf(target.prototype).constructor;
var parentAnnotations = Reflect.getMetadata('design:paramtypes', parentTarget);


Reflect.defineMetadata('design:paramtypes', parentAnnotations, target);


// Component annotations / metadata
var annotations = Reflect.getOwnMetadata('annotations', target);
annotations = annotations || [];
annotations.push(annotation);
Reflect.defineMetadata('annotations', annotations, target);
}
}

它将利用来自父构造函数的元数据,而不是它自己的元数据。您可以在子类中使用它:

@Injectable()
export class SomeService {
constructor(protected http:Http) {
}
}


@Component()
export class BaseComponent {
constructor(private service:SomeService) {
}
}


@CustomComponent({
(...)
})
export class TestComponent extends BaseComponent {
constructor() {
super(arguments);
}


test() {
console.log('http = '+this.http);
}
}

更多细节见下面的问题:

In the updated Angular where ngModules are used, you can create a variable available anywhere in the code:

应用程序模块中添加此代码

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


export let AppInjector: Injector;
    

export class AppModule {
constructor(private injector: Injector) {
AppInjector = this.injector;
}
}

现在,您可以使用 AppInjector在代码的任何地方查找任何服务。

import { AppInjector } from '../app.module';


const myService = AppInjector.get(MyService);

店铺服务

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

@Injectable()
export class StoreService {
static isCreating: boolean = false;
static instance: StoreService ;
    

static getInstance() {
if (StoreService.instance == null) {
StoreService.isCreating = true;
StoreService.instance = new StoreService ();
StoreService.isCreating = false;
}
return StoreService.instance;
}
constructor() {
if (!StoreService.isCreating) {
throw new Error('You can\'t call new in Singleton instances! Call StoreService.getInstance() instead.');
}
}
    

MyAlertMethod(){
alert('hi);
}
}

.ts

//call this service directly in .ts as below:-


StoreService.getInstance().MyAlertMethod();

在多次遇到这个问题之后,我设计了一个很好的方法来克服这个问题,即在 Angular Injector服务中使用 getter,而不是直接在构造函数中注入服务。这允许在引用之前构造服务时间。我的示例只使用服务,但同样的事情也可以应用到使用服务的组件中,只需将 getter 放在组件中,而不是放在示例中的 BService中。

我所做的是使用 getter 将服务注入到类属性中,如果之前没有设置 class 属性,那么服务只注入一次(第一次调用 getter 时)。这使得服务的使用方式基本上与在构造函数中注入的方式相同,但是没有循环引用错误。只要使用获取器 this.aService。只有当您试图在 Bservice的构造函数中使用 AService时,才会出现循环引用的问题,因为 Aservice还没有准备好。通过使用 getter,您可以将注入服务的时间推迟到您需要它的时候。

There are arguments that, AService depending on BService, and BService depending on AService, is bad form but there exceptions to every rule and every situation is different so this is an easy and effective way to deal with this issue in my opinion.

// a.service.ts
import { Injectable } from '@angular/core';


import { BService } from './b.service';


@Injectable({
providedIn: 'root'
})
export class AService {


constructor(
private bService: BService,
) { }


public foo() {
console.log('foo function in AService!');
this.bService.bar();
}
}
// b.service.ts
import { Injectable, Injector } from '@angular/core';


import { AService } from './a.service';




@Injectable({
providedIn: 'root'
})
export class BService {
// Use the getter 'aService' to use 'AService', not this variable.
private _aService: AService;


constructor(
private _injector: Injector,
) { }


// Use this getter to use 'AService' NOT the _aService variable.
get aService(): AService {
if (!this._aService) {
this._aService = this._injector.get(AService);
}
return this._aService;
}


public bar() {
console.log('bar function in BService!');
this.aService.foo();
}
}