上一篇說到了平臺實例在初始化的時候會建立根注入器,那如今就一塊兒看看注入器是如何建立的,又是如何工做的.(全部引用的代碼都被簡化了)數組
程序初始化時調用的建立根注入器的靜態方法:app
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
類型的實例(也就是注入器).ide
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); } }
注入器的構造函數在初始化過程當中的操做:this
_records
屬性,是一個Map
類型)providers
所有添加到註冊表中向註冊表中添加服務調用了recursivelyProcessProviders
函數prototype
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
函數具體的執行過程:code
若是provider
是個數組,那就遍歷後依次調用此方法.對象
若是provider
是個對象:token
1 獲取token
ip
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
類型的服務或此服務已經被建立過