Nest 实现了 IoC 容器,会从入口模块开始扫描,分析 Module 之间的引用关系,对象之间的依赖关系,自动把 provider 注入到目标对象。
而这个 provider 也有好几种,下面就来看一下。
可以看到 AppService 是被 @Injectable 修饰的 class。
在 Module 的 providers 里声明:
这就是 provider。
其实这是一种简写,完整的写法是这样的:
通过 provide 指定 token,通过 useClass 指定对象的类,Nest 会自动对它做实例化后用来注入。
在 AppController 的构造器里参数里声明了 AppService 的依赖,就会自动注入:
如果不想用构造器注入,也可以属性注入:
通过 @Inject 指定注入的 provider 的 token 即可。
有的同学说,在构造器参数里指定 AppService 的依赖的时候也没指定 token 啊?
那是因为 AppService 这个 class 本身就是 token。
当然,这个 token 也可以是字符串:
如果 token 是字符串的话,注入的时候就要用 @Inject 手动指定注入对象的 token 了:
相比之下,用 class 做 token 可以省去 @Inject,比较简便。
除了指定 class 外,还可以直接指定一个值,让 IoC 容器来注入。
使用 provide 指定 token,使用 useValue 指定值。
然后在对象里注入它:
provider 的值可能是动态产生的,Nest 也同样支持:
{
provide: 'person2',
useFactory() {
return {
name: 'bbb',
desc: 'cccc'
}
}
}
我们可以使用 useFactory 来动态创建一个对象。
在对象里注入:
这个 useFactory 支持通过参数注入别的 provider:
通过 inject 声明了两个 token,一个是字符串 token 的 person,一个是 class token 的 AppService。
也就是注入这两个 provider:
可以看到,在调用 useFactory 方法的时候,Nest 就会注入这两个对象。
useFactory 支持异步:
Nest 会等拿到异步方法的结果之后再注入。
这样就可以更灵活的创建注入对象。
此外,provider 还可以通过 useExisting 来指定别名:
{ provide: 'person4', useExisting: 'person2' }
这里就是给 person2 的 token 的 provider 起个新的 token 叫做 person4。
然后就可以用新 token 来注入了。
这些自定义 provider 的方式里,最常用的是 useClass,不过我们一般会用简写,也就是直接指定 class。
useClass 的方式由 IoC 容器负责实例化,我们也可以用 useValue、useFactory 直接指定对象。
useExisting 只是用来起别名的,有的场景下会用到。
总结
一般情况下,provider 是通过 @Injectable 声明,然后在 @Module 的 providers 数组里注册的 class。
默认的 token 就是 class,这样不用使用 @Inject 来指定注入的 token。
但也可以用字符串类型的 token,不过注入的时候要用 @Inject 单独指定。
除了可以用 useClass 指定注入的 class,还可以用 useValue 直接指定注入的对象。
如果想动态生成对象,可以使用 useFactory,它的参数也注入 IOC 容器中的对象,然后动态返回 provider 的对象。
如果想起别名,可以用 useExisting 给已有的 token,指定一个新 token。
灵活运用这些 provider 类型,就可以利用 Nest 的 IOC 容器中注入任何对象。