上一篇说到了平台实例在初始化的时刻会建立根注入器,那如今就一同看看注入器是怎样建立的,又是怎样事情的.(一切援用的代码都被简化了)
建立注入器
顺序初始化时挪用的建立根注入器的静态要领:
abstract class Injector{
static create(options: StaticProvider[]|{providers: StaticProvider[], parent?: Injector, name?: string},parent?: Injector): Injector {
if (Array.isArray(options)) {
return new StaticInjector(options, parent);
} else {
return new StaticInjector(options.providers, options.parent, options.name || null);
}
}
挪用此要领会返回一个StaticInjector
范例的实例(也就是注入器).
StaticInjector
类
export class StaticInjector implements Injector {
readonly parent: Injector;
readonly source: string|null;
private _records: Map<any, Record>;
constructor(providers: StaticProvider[], parent: Injector = NULL_INJECTOR, source: string|null = null) {
this.parent = parent;
this.source = source;
const records = this._records = new Map<any, Record>();
records.set(Injector, <Record>{token: Injector, fn: IDENT, deps: EMPTY, value: this, useNew: false});
records.set(INJECTOR, <Record>{token: INJECTOR, fn: IDENT, deps: EMPTY, value: this, useNew: false});
recursivelyProcessProviders(records, providers);
}
}
注入器的组织函数在初始化历程当中的操纵:
- 设置当前注入器的父注入器
- 设置注入器的源
- 新建注册表(
_records
属性,是一个Map
范例) - 将参数
providers
悉数增加到注册表中
向注册表中增加效劳挪用了recursivelyProcessProviders
函数
const EMPTY = <any[]>[];
const MULTI_PROVIDER_FN = function (): any[] { return Array.prototype.slice.call(arguments) };
function recursivelyProcessProviders(records: Map<any, Record>, provider: StaticProvider) {
if (provider instanceof Array) {
for (let i = 0; i < provider.length; i++) {
recursivelyProcessProviders(records, provider[i]);
}
} else (provider && typeof provider === 'object' && provider.provide) {
let token = resolveForwardRef(provider.provide);// 要领`resolveForwardRef`的作用多是向前兼容,能够疏忽
const resolvedProvider = resolveProvider(provider);
if (provider.multi === true) {
let multiProvider: Record | undefined = records.get(token);
if (multiProvider) {
if (multiProvider.fn !== MULTI_PROVIDER_FN) {
throw multiProviderMixError(token);
}
} else {
records.set(token, multiProvider = <Record>{
token: provider.provide,
deps: [],
useNew: false, // 这个值在后面猎取依靠实例的时刻会用到,当作推断前提
fn: MULTI_PROVIDER_FN,
value: EMPTY // 这个值在后面猎取依靠实例的时刻会用到,当作推断前提
});
}
token = provider;
multiProvider.deps.push({ token, options: OptionFlags.Default });
}
records.set(token, resolvedProvider);
}
}
recursivelyProcessProviders
函数详细的实行历程:
假如provider
是个数组,那就遍历后顺次挪用此要领.
假如provider
是个对象:
1 猎取token
let token = resolveForwardRef(provider.provide);
2 挪用resolveProvider
要领处置惩罚效劳中能够涌现的属性和依靠,返回一个Record
对象,此对象会作为token
的值<!– (useValue
,useClass
,deps
,useExisting
,useFactory
) –>
function resolveProvider(provider: SupportedProvider): Record {
const deps = computeDeps(provider);
let fn: Function = function (value) { return value };
let value: any = [];
// useUew用来标识是不是须要 new
let useNew: boolean = false;
let provide = resolveForwardRef(provider.provide);
if (USE_VALUE in provider) {
value = provider.useValue;
} else if (provider.useFactory) {
fn = provider.useFactory;
} else if (provider.useExisting) {
//do nothing
} else if (provider.useClass) {
useNew = true;
fn = resolveForwardRef(provider.useClass);
} else if (typeof provide == 'function') {
useNew = true;
fn = provide;
} else {
throw staticError('StaticProvider does not have [useValue|useFactory|useExisting|useClass] or [provide] is not newable', provider);
}
return { deps, fn, useNew, value }; // provider中差别的属性会返回包括差别值的对象
}
这个要领会先挪用computeDeps
函数处置惩罚效劳须要的依靠,它将useExisting
范例的效劳也转换成deps
,末了返回[{ token, OptionFlags }]
情势的数组(OptionFlags
是罗列常量)
function computeDeps(provider: StaticProvider): DependencyRecord[] {
let deps: DependencyRecord[] = EMPTY;
const providerDeps: any[] = provider.deps;
if (providerDeps && providerDeps.length) {
deps = [];
for (let i = 0; i < providerDeps.length; i++) {
let options = OptionFlags.Default;
let token = resolveForwardRef(providerDeps[i]);
deps.push({ token, options });
}
} else if ((provider as ExistingProvider).useExisting) {
const token = resolveForwardRef((provider as ExistingProvider).useExisting);
deps = [{ token, options: OptionFlags.Default }];
}
return deps;
}
resolveProvider
函数终究返回的Record
对象有一个缺省值:
{
deps:[], // 包括依靠时 [{ token, options },{ token, options }]
fn:function(value) { return value },
useNew:false,
value:[]
}
实行历程当中会依据provider
差别的属性修正Record
对象的变量为差别的值:
-
useValue
: 修正value
为useValue
的值 -
useFactory
: 修正fn
为对应的函数 -
useClass
或typeof provide == 'function'
(令牌为一个函数时) : 修正fn
为对应的函数,并设置useNew
为true
-
useExisting
: 不做修正,直接运用默认值
3 假如是多处置惩罚效劳(multi:ture
)且为初次注册,那末在注册表中分外注册一个占位的Record
records.set(token, multiProvider = <Record>{
token: provider.provide,
deps: [],
useNew: false,
fn: MULTI_PROVIDER_FN,
value: EMPTY
});
4 非多处置惩罚效劳以token
为键,多处置惩罚效劳以provider
对象为键,返回的Record
对象为值,存入注册表records
中
从注入器中猎取实例
效劳注册完,下一步就是怎样从注入器中猎取效劳的实例了,这会挪用StaticInjector
的get
要领
export class StaticInjector implements Injector {
get(token: any, notFoundValue?: any, flags: InjectFlags = InjectFlags.Default): any {
// 猎取token对应的record
const record = this._records.get(token);
return resolveToken(token, record, this._records, this.parent, notFoundValue, flags);
}
get
要领挪用了resolveToken
函数,这个函数会返回token
对应的实例(就是被注入的对象)
const EMPTY = <any[]>[];
const CIRCULAR = IDENT;
const IDENT = function <T>(value: T): T { return value };
function resolveToken(token: any, record: Record | undefined, records: Map<any, Record>, parent: Injector,
notFoundValue: any, flags: InjectFlags): any {
let value;
if (record && !(flags & InjectFlags.SkipSelf)) {
value = record.value;
if (value == CIRCULAR) {
throw Error(NO_NEW_LINE + 'Circular dependency');
} else if (value === EMPTY) {
record.value = CIRCULAR;
let obj = undefined;
let useNew = record.useNew;
let fn = record.fn;
let depRecords = record.deps;
let deps = EMPTY;
if (depRecords.length) {
deps = [];
for (let i = 0; i < depRecords.length; i++) {
const depRecord: DependencyRecord = depRecords[i];
const options = depRecord.options;
const childRecord = options & OptionFlags.CheckSelf ? records.get(depRecord.token) : undefined;
deps.push(tryResolveToken(
depRecord.token,
childRecord,
records,
!childRecord && !(options & OptionFlags.CheckParent) ? NULL_INJECTOR : parent,
options & OptionFlags.Optional ? null : Injector.THROW_IF_NOT_FOUND,
InjectFlags.Default));
}
}
record.value = value = useNew ? new (fn as any)(...deps) : fn.apply(obj, deps);
}
} else if (!(flags & InjectFlags.Self)) {
value = parent.get(token, notFoundValue, InjectFlags.Default);
}
return value;
}
函数中会先推断当前要求的token
是不是存在,假如不存在则去当前注入器的父注入器中寻觅,假如存在:
猎取token
对应的record
推断record.value
是不是为[]
(非useValue
范例的效劳/多处置惩罚效劳的默认值是[]
):
ture
: 非useValue
范例的效劳/多处置惩罚效劳或此效劳没有被建立过
- 检察是不是包括依靠,包括则优先建立依靠的实例,也是挪用这个函数
- 依据
record.fn
建立当前token
对应的实例并更新record.value
(这里须要依据record.useNew
来推断是不是须要用new
来实例化,比方useFactory
范例就不须要new
,而useExisting
更是直接返回了deps
) - 返回这个值
false
: useValue
范例的效劳或此效劳已被建立过
- 直接返回这个值