angular源码分析之StaticInjector
上一篇说到了平台实例在初始化的时候会创建根注入器,那现在就一起看看注入器是如何创建的,又是如何工作的.(所有引用的代码都被简化了)
创建注入器
程序初始化时调用的创建根注入器的静态方法:
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
类型的服务或此服务已经被创建过
- 直接返回这个值