Angular2 依赖注入之实例化过程

来源:互联网 发布:linux修改ip的命令 编辑:程序博客网 时间:2024/05/22 03:41

上一篇讲了Angular 依赖注入之注解

这里会介绍 Angular 的注入器和实例化过程,基于 angular@4.1.0-beta.1

Angular 依赖注入过程主要有下面几个重要的部分组成:

  • Inject 和 Injectable 装饰器
  • 解析提供商,构造注入器
  • 获取实例化对象

Angular 依赖注入中的一些重要的概念:

Provider :
提供商,下面就是一个Proviver,一共有5种构造提供商的方式:TypeProvider, ValueProvider, ClassProvider, ExistingProvider, FactoryProvider

{ provide: Logger, useClass: Logger }

Token :
令牌,提供商中的第一个参数就是Token,在查找依赖时作为 key 使用。

Injector :
注入器,用于解析依赖和创建对象。

Example

class Engine {  start() {    console.log('engine start');  }}class Car {  engine: Engine;  constructor(@Inject(Engine) engine) {    this.engine = engine;  }  open() {    this.engine.start();    console.log('car open');  }}let inj = ReflectiveInjector.resolveAndCreate([    Car,    Engine]);let car = inj.get(Car);car.open();

2. 解析服务提供商,构造注入器

在上面注解完成之后,接下来可以构造 Injector,Injector 首先需要解析 Provider.

let inj = ReflectiveInjector.resolveAndCreate([  {provide:Car,useClass:Car},  {provide:Engine,useClass:Engine}]);

Provider 的解析主要由 resolveReflectiveProviders() 来完成,解析过程主要分为

  • provider 参数预处理
  • 解析实例化工厂及其依赖
  • 合并提供商
  • 构造注入器

下面是解析过程的源码

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());}


2.1 参数预处理

_normalizeProviders 是将 provider 参数标准化,将省略了 useClass 的补全,将嵌套的 Provider 数组拍平

function _normalizeProviders(providers: Provider[], res: Provider[]): Provider[] {  providers.forEach(b => {    //如果 provider 是构造函数,对应没有提供useClass的情况    if (b instanceof Type) {      res.push({provide: b, useClass: b});    //如果是对象,且带provide属性,直接放入数组    } else if (b && typeof b == 'object' && (b as any).provide !== undefined) {      res.push(b as NormalizedProvider);    //如果是数组,递归拍平    } else if (b instanceof Array) {      _normalizeProviders(b, res);    } else {      throw invalidProviderError(b);    }  });  return res;}


2.2 解析实例化工厂及其依赖

resolveReflectiveProvider 函数会根据 ReflectiveKey 和 ResolvedReflectiveFactory 返回一个 ResolvedReflectiveProvider_ 对象。

function resolveReflectiveProvider(provider: NormalizedProvider): ResolvedReflectiveProvider {  return new ResolvedReflectiveProvider_(      ReflectiveKey.get(provider.provide), [resolveReflectiveFactory(provider)],      provider.multi || false);}

其中的 resolveReflectiveFactory() 函数是其中的重点,解析的实例化工程和以来的方式有4钟,分别对应 4种 Provider 的创建方式,分别是

  • useClass
  • useExisting
  • useFactory
  • useValue

这个函数里面会根据这四种方式提供不同的实例化工厂和依赖解析,依赖解析完成会返回一个 ReflectiveDependency 数组。

ReflectiveDependency 的构造函数为

constructor(      public key: ReflectiveKey, public optional: boolean,       public visibility: Self|SkipSelf|null)

ReflectiveKey 有两个属性: id 和 token ,其内部维持了一个Map

2.2.1 useClass

实例化工厂

useClass 的情况下实例化就通过 new 的方式完成

factoryFn = (...args: any[]) => new t(...args)

依赖解析方式

从 Inject 和 Injectable 两个装饰器中保存的信息寻找依赖的构造函数,也就是从 ‘parameters’ 和 ‘design:paramtypes’ 两个元数据中寻找。如果当前构造函数没有,回从原型链向上查找

2.2.2 useExisting

实例化工厂

useExisting 情况下是一个返回传入参数的函数,也就是返回依赖的实例

factoryFn = (aliasInstance: any) => aliasInstance;

依赖解析方式

将 useExisting 的值作为其依赖,也就是作为后面实例化时的参数

[ReflectiveDependency.fromKey(ReflectiveKey.get(provider.useExisting))]


2.2.3 useFactory

实例化工厂

useFactory 的情况下就是useFactory的值

factoryFn = provider.useFactory;

依赖解析方式

如果定义了 deps,则直接从 deps 中抽取出 token 并构造ReflectiveDependency

否则使用和 useClass 相同的方法解析依赖

2.2.4 useValue

实例化工厂

直接返回这个值

factoryFn = () => provider.useValue;

依赖解析方式

空数组


2.3 合并提供商

Angular 允许为一个 token 提供多个 provider, 只要申明 multi:true 即可。

let inj = ReflectiveInjector.resolveAndCreate([{provide:Car,useClass:Car,multi:true},{provide:Car,useClass:SuperCar,multi:true},{provide:Engine,useClass:Engine}]);let car = inj.get(Car); //car = [Car, SuperCar]

此时使用 injector.get() 方法返回的是一个数组。 Angular 使用这种机制来提供可插拔的接口(pluggable hooks).

mergeResolvedReflectiveProviders() 函数就是用来处理多提供商的情况的,对申明 multi:true 的提供商,它会为一个 token 提供多个值。

2.4 构造注入器

ReflectiveInjector 的构造器如下,使用上面解析完成的 ResolvedReflectiveProvider_ 和父注入器实例化。

constructor(_providers: ResolvedReflectiveProvider[], _parent?: Injector)


3. 从注入器获取对象

从注入器中获取对象主要分为以下几步:

  • 判断从哪个注入器获取对象
  • 从缓存中查找
  • 实例化对象及其依赖

3.1 判断 Self 和 SkipSelf

默认是如果当前注入器没找到,则递归向父注入器查找

self 只从当前注入器查找
SkipSelf 从父注入器开始查找

while (inj instanceof ReflectiveInjector_) {  const inj_ = <ReflectiveInjector_>inj;  const obj = inj_._getObjByKeyId(key.id);  if (obj !== UNDEFINED) return obj;  inj = inj_._parent;}


3.2 缓存

ReflectiveInjector_ 对象中有两名两个属性,主要用于缓存对象。 keyIds 是所有 ReflectiveKey 的 id, objs 是缓存的已经实例化的对象。

keyIds: number[];objs: any[];

根据 ReflectiveKey 的 Id 判断是否已经实例化。 如果没有就 new 一个。

private _getObjByKeyId(keyId: number): any {  for (let i = 0; i < this.keyIds.length; i++) {    if (this.keyIds[i] === keyId) {      if (this.objs[i] === UNDEFINED) {        //实例化对象,并缓存到objs        this.objs[i] = this._new(this._providers[i]);      }      return this.objs[i];    }  }  return UNDEFINED;}


3.3 实例化

实例化对象会首先实例化其需要的依赖,然后再根据由其实例化工厂来处理。

private _instantiate(    provider: ResolvedReflectiveProvider,    ResolvedReflectiveFactory: ResolvedReflectiveFactory): any {  const factory = ResolvedReflectiveFactory.factory;  let deps: any[];  try {    //实例化所有依赖    deps =        ResolvedReflectiveFactory.dependencies.map(dep => this._getByReflectiveDependen(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;}
1 0
原创粉丝点击