![](/img/trans.png)
[英]what is the difference between @Inject(Injector) injector and injector?
[英]Difference between Reflective Injector and Injector in Angular
我試圖使用兩種方法顯式創建依賴關系。 兩者幾乎相同,但我有點混淆使用反射式噴射器比普通噴射器的優勢,推薦哪種方式?
使用噴油器
import { Injector } from '@angular/core';
constructor( private injector: Injector) {
this.myService = this.injector.get(MyService);
}
使用反射式噴油器
import { ReflectiveInjector } from '@angular/core';
constructor() {
var injector= ReflectiveInjector.resolveAndCreate([MyService]);
let myservice=injector.get(MyService);
}
注射器是帶有提供者/服務的容器。 它實現一種方法get
並返回服務的實例。 讓我們用JS偽代碼實現注入器的最基本版本:
class ReflectiveInjector {
providers = [];
static resolveAndCreate(providers) {
providers.forEach((provider)=>{
providers.push({token: provider.provide, instance: new provider.useClass})
});
)}
get(dep) {
return providers.find((provider)=>{ return provider.token === token });
}
}
現在,我們需要先創建注入器的實例,然后才能使用它。 當我們創建它時,我們定義了提供者:
const existingInjector = ReflectiveInjector.resolveAndCreate([{provide: A, useClass: A }]);
const AInstance = existingInjector.get(A);
因此,您看到為了使用注射器,必須首先創建它。 它沒有允許添加提供者的任何特定方法,因此在創建之后,我們無法向其添加任何新的提供者。
Angular 已經創建了您注入到組件構造函數中的注入器。 您不能向其添加任何內容,並且只能查詢已經在其上定義的提供程序。 如果需要提供B
級,則無法使用現有的進樣器進行。 您需要一個新的。 這就是ReflectiveInjector
類的來源。它允許您通過創建注射器的新實例並注冊新的提供程序來添加新的提供程序。 好處是它還可以設置噴射器鏈。
讓我們修改resolveAndCreate
並get
允許鏈接注入器的方法:
class ReflectiveInjector {
providers = [];
parent;
static resolveAndCreate(providers, parent) {
this.parent = parent;
...
}
get(dep) {
let found = providers.find((provider)=>{ return provider.token === token });
if (!found && parent) {
found = parent.get(dep);
}
return found;
}
所以現在剩下的就是使用它:
// passing existingInjector as a parent
const childInjector = ReflectiveInjector.resolveAndCreate([{provide: B, useClass: B }], i);
const AInstance = childInjector.get(A);
const BInstance = childInjector.get(B);
現在,假設有人可能想要訪問我們existingInjector
。 我們需要一個令牌來獲取這個現有的注射器。 讓我們這樣定義令牌:
abstract class Injector {}
並編寫一個可以獲取現有注射器的函數:
function resolveDependency(token) {
if (token === Injector) {
return existingInjector;
}
}
現在假設Angular在執行組件的構造函數,使用您指定的標記獲取依賴項並將它們傳遞給resolveDependency
函數時。 所以你這樣寫:
// the Injector here is a reference to our abstract Injector class and simply used as a token
MyComp {
constructor(private injector: Injector) { ... }
}
這里的令牌是Injector
,正如我所說的,它被傳遞到resolveDependency
函數中,並返回現有的注射器。
Angular只會為每個提供程序創建一次實例。 因此,如果您想將Injector
用作工廠,則不能。 您必須為所需對象的每個新實例創建一個新的注射器。
假設我們有一個名為ReportsService
的服務類,它需要在運行時創建Record
對象,但是您希望Record
是可注入的。
這是我們需要創建其多個實例的類。
@Injectable() // does not have to be defined in ngModule
export class Record {
// just an example dependency that ReportsService doesn't know about
public constructor(http: Http) {
}
}
這是將創建上述類的服務。
@Injectable() // exported via ngModule
export class RecordsService {
// we need injector as parent otherwise Record class will not find Http
public constructor(private parent: Injector) {
}
// factory method
public createRecord(): Record {
// creates a new injector that knows about Record but extends existing injector
let injector = ReflectiveInjector.resolveAndCreate([
{provide: Record, useClass: Record}
], this.parent);
// first call, object is created
let record = injector.get(Record);
// just an example
let example = injector.get(Record);
// will output true
console.log(record === example ? 'true' : 'false');
return record;
}
}
現在,一個新的Record實例很棒,但是如果每個對象都完全相同又有什么用呢? 因此,我們需要為Record
注入參數。 我們將為字符串值創建令牌。
export const RECORD_URL = new InjectionToken<string>('record-url');
@Injectable()
export class Record {
public constructor(http: Http, @Inject(RECORD_URL) url: string) {
}
}
現在更新創建功能
public createRecord(url: string): Record {
let injector = ReflectiveInjector.resolveAndCreate([
{provide: Record, useClass: Record},
{provide: RECORD_URL, useValue: url
], this.parent);
return injector.get(Record);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.