使用装饰器注入
如果每次代码都需要手动绑定,然后通过 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 仓库的 OrdinaryGetPrototypeOf 方法,使用 recursiveGetPrototypeOf
方法以数组形式返回该类的所有原型。
function recursiveGetPrototypeOf(target: any): any[] {
const properties = [];
let parent = ordinaryGetPrototypeOf(target);
while (parent !== null) {
properties.push(parent);
parent = ordinaryGetPrototypeOf(parent);
}
return properties;
}