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;constructor(providers: StaticProvider[], parent: Injector = NULL_INJECTOR, source: string|null = null) {this.parent = parent;this.source = source;const records = this._records = new Map();records.set(Injector, {token: Injector, fn: IDENT, deps: EMPTY, value: this, useNew: false});records.set(INJECTOR, {token: INJECTOR, fn: IDENT, deps: EMPTY, value: this, useNew: false});recursivelyProcessProviders(records, providers);}
} 注入器的构造函数在初始化过程中的操作:
- 设置当前注入器的父注入器
- 设置注入器的源
- 新建注册表(
_records属性,是一个Map类型) - 将参数
providers全部添加到注册表中
向注册表中添加服务调用了recursivelyProcessProviders函数
const EMPTY = [];
const MULTI_PROVIDER_FN = function (): any[] { return Array.prototype.slice.call(arguments) };
function recursivelyProcessProviders(records: Map, 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 = {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的值
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 = {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对应的recordconst record = this._records.get(token);return resolveToken(token, record, this._records, this.parent, notFoundValue, flags);
} get方法调用了resolveToken函数,这个函数会返回token对应的实例(就是被注入的对象)
const EMPTY = [];
const CIRCULAR = IDENT;
const IDENT = function (value: T): T { return value };
function resolveToken(token: any, record: Record | undefined, records: Map, 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类型的服务或此服务已经被创建过
- 直接返回这个值
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
