Injector的實現(xiàn)原理

在分析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聲明的了多個,就會拋出異常。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容