我在bootstrap中定义了@Injectable
服务。我想在不使用构造函数注入的情况下获取服务的实例。我尝试使用ReflectiveInjector.resolveAndCreate
但似乎创建了一个新实例。
我试图做的原因是我有一个由许多组件派生的基本组件。现在我需要访问服务,但我不想将它添加到ctor,因为我不想在所有派生组件上注入服务。
TLDR:我需要ServiceLocator.GetInstance<T>()
更新:RC5 +的更新代码:Storing injector instance for use in components
答案 0 :(得分:49)
是的,ReflectiveInjector.resolveAndCreate()
创建一个新的未连接的注入器实例。
您可以使用
注入AngularsInjector
实例并从中获取所需的实例
constructor(private injector:Injector) {
injector.get(MyService);
}
您还可以将Injector
存储在某个全局变量中,然后使用此注入器实例来获取提供的实例,例如https://github.com/angular/angular/issues/4112#issuecomment-153811572中所述
答案 1 :(得分:21)
在使用ngModules的更新的Angular中,您可以在代码中的任何位置创建可用的变量:
export let AppInjector: Injector;
export class AppModule {
constructor(private injector: Injector) {
AppInjector = this.injector;
}
}
答案 2 :(得分:5)
另一种方法是定义一个自定义装饰器(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);
}
}
有关详细信息,请参阅此问题:
答案 3 :(得分:0)
在遇到这个问题几次后,我设计了一个很好的方法来克服它,通过在 Angular Injector
服务中使用 getter,而不是直接将服务注入构造函数中。这允许在被引用之前构造服务时间。我的示例仅使用服务,但同样的事情可以应用于使用服务的组件,只需将 getter 放在组件中而不是示例中的 BService
。
我所做的是使用 getter 将服务注入使用 Injector
类的类属性,如果类属性之前尚未设置,则该服务仅注入一次(第一次调用吸气剂)。这允许服务的使用方式与在构造函数中注入的方式基本相同,但不会出现循环引用错误。只需使用吸气剂 this.aService
。只有当这不起作用时,如果您尝试在 AService
的构造函数中使用 Bservice
,那么您将遇到相同的循环引用问题,因为 Aservice
不会准备好了吗。 通过使用 getter,您可以推迟注入服务,直到您需要它。
有一些论点,AService
依赖于 BService
,而 BService
依赖于 AService
,是不好的形式,但每个规则都有例外,每种情况都不同,所以在我看来,这是处理这个问题的一种简单有效的方法。
// 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();
}
}
答案 4 :(得分:-1)
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);
}
}
//call this service directly in component.ts as below:-
StoreService.getInstance().MyAlertMethod();