在分析bootstrapModule方法時,我們發(fā)現(xiàn)當需要一個類的事例的時候只需要調(diào)用injector.get方法就能夠得到。這個Injector就是Angular依賴注入的基礎(chǔ),任何可以被注入的類都是都可以通過injector.get方法來獲取。
調(diào)用injector.get方法的時候會出現(xiàn)一下幾種情況:
1、如果以前沒有創(chuàng)建過,就會new一個事例,并返回。
2、如果以前創(chuàng)建過,就返回以前創(chuàng)建的那個事例,相當于單例模式。
Injector.get方法的調(diào)用過程
Injector是一個接口,實際實例化的類為ReflectiveInjector_。繼承關(guān)系為
ReflectiveInjector_ -> ReflectiveInjector -> Injector。
查看ReflectiveInjector_.get方法的代碼,我們可以發(fā)現(xiàn)其調(diào)用關(guān)系為:
get -> _getByKey -> _getByKeyDefault -> _getObjByKeyId
如果調(diào)用自己的_getObjByKeyId沒有找到實例,就會查找父Injector的_getObjByKeyId,一直向上查找。
在_getObjByKeyId如果具有聲明但是沒有事例化,就會去實例化并返回,具體代碼如下:
private _getObjByKeyId(keyId: number): any {
for (let i = 0; i < this.keyIds.length; i++) {
if (this.keyIds[i] === keyId) {
if (this.objs[i] === UNDEFINED) {
this.objs[i] = this._new(this._providers[i]);
}
return this.objs[i];
}
}
return UNDEFINED;
}
實例化的過程
實例化是通過調(diào)用_new方法來完成的,具體代碼為:
_new(provider: ResolvedReflectiveProvider): any {
if (this._constructionCounter++ > this._getMaxNumberOfObjects()) {
throw cyclicDependencyError(this, provider.key);
}
return this._instantiateProvider(provider);
}
在這段代碼中具有一個防止循環(huán)依賴的檢驗。
接下來就是使用provider中的創(chuàng)建工廠來創(chuàng)建實例了,具體代碼為:
private _instantiate(
provider: ResolvedReflectiveProvider,
ResolvedReflectiveFactory: ResolvedReflectiveFactory): any {
const factory = ResolvedReflectiveFactory.factory;
let deps: any[];
try {
deps =
ResolvedReflectiveFactory.dependencies.map(dep => this._getByReflectiveDependency(dep));
} catch (e) {
if (e.addKey) {
e.addKey(this, provider.key);
}
throw e;
}
let obj: any;
try {
obj = factory(...deps);
} catch (e) {
throw instantiationError(this, e, e.stack, provider.key);
}
return obj;
}
其中_getByReflectiveDependency方法會去查找依賴的事例,如果依賴的事例沒有被創(chuàng)建,就會先去創(chuàng)建,這里就會有可能造成循環(huán)依賴。
什么是Provider
Provider可以理解為是Angular對于依賴注入項的一個描述,一個對象可以被依賴注入,就必須有一個Provider對其進行描述。Injector根據(jù)這個Provider才能夠創(chuàng)建實例。
Provider源碼:
export interface TypeProvider extends Type<any> {}
export interface ValueProvider {
provide: any;
useValue: any;
multi?: boolean;
}
export interface ClassProvider {
provide: any;
useClass: Type<any>;
multi?: boolean;
}
export interface ExistingProvider {
provide: any;
useExisting: any;
multi?: boolean;
}
export interface FactoryProvider {
provide: any;
useFactory: Function;
deps?: any[];
multi?: boolean;
}
export type Provider =
TypeProvider | ValueProvider | ClassProvider | ExistingProvider | FactoryProvider | any[];
從源碼我們可以知道總共可以有5中類型的Provider以及一個數(shù)組類型的Provider。對于不同類型的Provider也有各自的定義和用法。
| 類型 | 說明 |
|---|---|
| TypeProvider | 任意類型的類,任意一個類都可以成為一個Provider,Angular會對其進行包裝,F(xiàn)actory就是new一個這個類型的事例,都是單例的 |
| ValueProvider | 使用具體的值作為實例的 |
| ClassProvider | 使用具體class來創(chuàng)建事例,和TypeProvider類似,但是可以設置為multi |
| ExistingProvider | 使用一個已有的Provider,相當于給已有的Provider設置一個別名 |
| FactoryProvider | 使用自己的創(chuàng)建工廠來實例化Provider,可以設置創(chuàng)建的依賴項 |
Injector在創(chuàng)建一個事例的時候就是使用Provider的Factory和deps來實例化(具體如上面的代碼所示)。
每一種Provider的Factory是怎么來的
從上面的分析我們可以發(fā)現(xiàn),這么多種Provider中只有FactoryProvider是需要設置Factory和deps的,然而在Injector創(chuàng)建實例的時候是必須需要Factory的,那么其它類型的Provider的Factory又是怎么來的呢?
通過跟蹤代碼,我們可以發(fā)現(xiàn)如下代碼:
function resolveReflectiveFactory(provider: NormalizedProvider): ResolvedReflectiveFactory {
let factoryFn: Function;
let resolvedDeps: ReflectiveDependency[];
if (provider.useClass) {
const useClass = resolveForwardRef(provider.useClass);
factoryFn = reflector.factory(useClass);
resolvedDeps = _dependenciesFor(useClass);
} else if (provider.useExisting) {
factoryFn = (aliasInstance: any) => aliasInstance;
resolvedDeps = [ReflectiveDependency.fromKey(ReflectiveKey.get(provider.useExisting))];
} else if (provider.useFactory) {
factoryFn = provider.useFactory;
resolvedDeps = constructDependencies(provider.useFactory, provider.deps);
} else {
factoryFn = () => provider.useValue;
resolvedDeps = _EMPTY_LIST;
}
return new ResolvedReflectiveFactory(factoryFn, resolvedDeps);
}
從這段代碼可以發(fā)現(xiàn),Angular我們定義的Provider從新計算了他們的Factory和deps。
Inectory自身的創(chuàng)建過程
通過調(diào)用ReflectiveInjector.resolveAndCreate方法可以創(chuàng)建一個Injector,這個方法的第一個參數(shù)就是我們需要使用到的Provider列表,第二個參數(shù)就是父Injector。
static resolveAndCreate(providers: Provider[], parent: Injector = null): ReflectiveInjector {
const ResolvedReflectiveProviders = ReflectiveInjector.resolve(providers);
return ReflectiveInjector.fromResolvedProviders(ResolvedReflectiveProviders, parent);
}
這個方法里面主要完成兩個動作:
1、格式化Provider。
2、new一個Injector事例。
第二步比較清晰,下面主要分析第一步。
第二步主要的代碼:
export function resolveReflectiveProviders(providers: Provider[]): ResolvedReflectiveProvider[] {
const normalized = _normalizeProviders(providers, []);
const resolved = normalized.map(resolveReflectiveProvider);
const resolvedProviderMap = mergeResolvedReflectiveProviders(resolved, new Map());
return Array.from(resolvedProviderMap.values());
}
這里主要做的事情有:
1、把provider列表理順,如:[[p1,p2],p3,[p4,p5]]理順為[p1,p2,p3,p4,p5]
2、封裝provider,就是上面添加Factory和deps的內(nèi)容。
3、合并相同的Provider,如果不支持multi的Provider聲明的了多個,就會拋出異常。