Angular 在没有构造函数注入的情况下获取服务实例
我在bootstrap中定义了一个Angular 在没有构造函数注入的情况下获取服务实例,angular,angular2-di,angular2-injection,Angular,Angular2 Di,Angular2 Injection,我在bootstrap中定义了一个@Injectable服务。我希望在不使用构造函数注入的情况下获取服务的实例。我尝试使用ReflectiveInjector.resolveAndCreate,但这似乎创建了一个新实例 我尝试这样做的原因是我有一个由许多组件派生的基本组件。现在我需要访问一个服务,但我不想将其添加到ctor中,因为我不想在所有派生组件上注入该服务 TLDR:我需要一个ServiceLocator.GetInstance() 更新:更新了RC5+的代码:是,ReflectiveIn
@Injectable
服务。我希望在不使用构造函数注入的情况下获取服务的实例。我尝试使用ReflectiveInjector.resolveAndCreate,但这似乎创建了一个新实例
我尝试这样做的原因是我有一个由许多组件派生的基本组件。现在我需要访问一个服务,但我不想将其添加到ctor中,因为我不想在所有派生组件上注入该服务
TLDR:我需要一个ServiceLocator.GetInstance()
更新:更新了RC5+的代码:是,
ReflectiveInjector.resolveAndCreate()
创建一个新的未连接的注入器实例
您可以注入AngularsInjector
实例,并使用
构造函数(专用注入器:注入器){
获取(MyService);
}
您还可以将
注入器
存储在某个全局变量中,然后使用此注入器实例获取提供的实例,例如,如中所述。另一种方法包括定义自定义装饰器(一个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);
}
}
有关更多详细信息,请参见此问题:
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);
商店服务
组件技术
在多次遇到这个问题后,我设计了一个很好的方法来克服它,通过将getter与Angular
Injector
服务一起使用,而不是直接将服务注入构造函数。这允许在引用之前构造服务时间。我的示例仅使用服务,但同样的事情也可以应用于使用服务的组件,只需将getter放在组件中,而不是示例中的BService
我所做的是使用getter,使用Injector
类将服务注入class属性,如果class属性以前没有设置,那么服务只注入一次(第一次调用getter)。这允许服务的使用方式与在构造函数中注入时基本相同,但没有循环引用错误。只需使用getterThis.aService
。只有当您试图在Bservice
的构造函数中使用aService
时,这才不会起作用,然后您将拥有same由于a服务
尚未准备就绪,因此发出循环引用。通过使用getter,您将推迟注入服务,直到您需要它。
有人认为,AService
依赖于BService
,BService
依赖于AService
,这是一种不好的形式,但每个规则都有例外,每种情况都不同,所以我认为这是一种简单有效的方法来处理这个问题
//a.service.ts
从“@angular/core”导入{Injectable};
从“/b.service”导入{BService};
@注射的({
providedIn:'根'
})
导出类服务{
建造师(
私人bService:bService,
) { }
公共食物({
log('AService中的foo函数!');
这个.bService.bar();
}
}
//b.service.ts
从“@angular/core”导入{Injectable,Injector};
从“/a.service”导入{AService};
@注射的({
providedIn:'根'
})
导出类BService{
//使用getter“aService”来使用“aService”,而不是这个变量。
私人服务:私人服务;
建造师(
专用注射器:注射器,
) { }
//使用此getter可以使用'AService'而不是_AService变量。
获取aService():aService{
如果(!本服务){
此.\u aService=此.\u injector.get(aService);
}
把这个还给服务部;
}
公共酒吧(){
log('BService中的bar函数!');
this.aService.foo();
}
}
将注入器存储在bootstrap中的全局变量中。然后()听起来像我需要的。问题是没有构造函数,这使得这个答案毫无帮助。如果构造函数在组件中,则是组件注入器,在服务中是模块注入器(如果不是延迟加载的模块,则基本上是根注入器)。您还可以通过添加@SkipSelf()
来获取父组件注入器。您还可以交互父组件
getter以获取根注入器。@Rhyous magic?您可以在静态字段或全局变量中共享注入器并从那里访问它,但首先需要在“某处”注入它使用构造函数并将其分配给静态字段。DI容器ng是否使用得那么糟糕,甚至不支持普通DI容器的基本功能?问题是tsc不允许我调用super(参数)因为基本构造函数的参数不匹配。在这种特殊情况下,我们可以从派生类中删除构造函数。这可能也是一个很好的答案。你是国王!哇,我们可以这样做吗?这有一个小问题。你必须为提供服务的延迟加载模块制作单独的注入器。是的,这怎么可能使用需要在构造函数中注入其他服务的服务?
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();