使用装饰器注入

使用装饰器注入

如果每次代码都需要手动绑定,然后通过 get/getAsync 方法拿到对应的对象,那将会非常繁琐,由于 在设计之初 midway/injection 体系就基于 ts,参考了业界的 IoC 实现,完成了属于自己的依赖注入能力,主要是通过 @provide 和 @inject 两个装饰器来完成绑定定义和自动注入属性,大大简化了代码量。

TIP

由于使用了依赖注入体系,我们希望所有的业务代码都通过 class 语法来完成

@provide()
export class UserService {

  @inject()
  userModel;

  async getUser(userId) {
    return await this.userModel.get(userId);
  }
}

我们可以看到业务代码的样子和以往有着一些不同。

  • 类加了装饰器,同时直接导出,不需要关心如何实例化
  • 属性加了装饰器,但是没有任何初始化以及赋值的操作即可使用

@provide()

有了 @provide() 装饰器,就可以简化绑定,被 IoC 容器自动扫描,并绑定定义到容器上,对应的逻辑是 绑定对象定义。

@provide(id?) 的参数为对象 id,可选。

注意

@provide 装饰器是用于自动被 IoC 容器装载。

@inject()

@inject() 的作用是将容器中的定义实例化成一个对象,并且绑定到属性中,这样,在调用的时候就可以访问到该属性。

注意

注入的时机为构造器(new)之后,所以在构造方法(constructor)中是无法获取注入的属性的,如果要获取注入的内容,可以使用 构造器注入。

父类的属性使用 @inject() 装饰器装饰,子类实例会得到装饰后的属性。

class Parent {
  @inject()
  katana1;
}

class Child extends Parent {
  @inject()
  katana2;
}

class Grandson extends Child {
  @inject()
  katana3;
}

Grandson 的实例 grandson 拥有 @inject() 装饰器注入的 grandson.katana3, grandson.katana2, grandson.katana1 属性。

实现时,会查找 Gradson 的原型链,遍历原型链上所有用 @inject() 装饰的属性,运行装饰器,注入相应的属性。

查找类的原型使用 reflect-metadata 使用装饰器注入 - 图1 仓库的 OrdinaryGetPrototypeOf 使用装饰器注入 - 图2 方法,使用 recursiveGetPrototypeOf 方法以数组形式返回该类的所有原型。

function recursiveGetPrototypeOf(target: any): any[] {
  const properties = [];
  let parent = ordinaryGetPrototypeOf(target);
  while (parent !== null) {
    properties.push(parent);
    parent = ordinaryGetPrototypeOf(parent);
  }
  return properties;
}