providers 使用
该内容可以结合 Nestjs 中文网-自定义提供者 查看
创建一个 nest 项目,创建一个 Person crud模块。
providers 写法
providers 完整和简写
@Injectable()
装饰器将 PersonService 类标记为提供者。然后在 Module 中声明,即和 PersonService 做关联,个人感觉 providers
的主要作用就是去关联 Service 层。
providers
有两种写法,简化写法 和 完整写法,常用是简化写法
// 简化写法
@Module({
providers: [PersonService],
})
// 完整写法
@Module({
providers: [
{
provide: PersonService,
useClass: PersonService,
},
],
})
而在 Module 中关联 Service 之后,Nest 就会自动做实例化并注入。
Controller 层在使用时,会自动注入
如果不想使用 constructor 构造器注入,也可以手动注入
@Controller('person')
export class PersonController {
@Inject(PersonService)
private readonly personService: PersonService;
// constructor(private readonly personService: PersonService) {}
@Get()
findAll() {
return this.personService.findAll();
}
}
providers 的属性
token 字符串写法
providers 的完整写法中,provide
通常是 xxxService,也就是 class,但也可以是字符串
调试,可以得出该方法也同样可以注入
当使用完整写法,且 provide
声明的 token 是字符串时,必须手动 @Inject
注入 token,不简洁,因此该方式并不常用
useValue
对模块提供部分静态数据,可以使用 useValue
providers: [
{
provide: 'person_static_value',
useValue: {
name: '张三',
age: 20,
},
},
],
切记,一个 provide
中,useClass
和 useValue
不能同时出现,否则 useValue
无效
useFactory
useValue
提供的是静态值,useFactory
提供的就是动态值,类似于工厂模式,对于工厂模式的应用可阅读 该掘金作者文章
providers: [
{
provide: 'person_factory',
useFactory() {
const a = 10;
if (a == 10) {
return { cat: '狸花', dog: '土狗',};
}
return {};
},
},
],
同时,useFactory
也支持异步注入
const sleep = (time = 1000) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ cat: '狸花', dog: '土狗' });
}, time);
});
};
providers: [
{
provide: 'person_factory',
useFactory: async () => {
const res = await sleep(5000);
return res;
},
},
],
以上例子中,useFactory
在 5s 后返回数据,则注入也是在 5s 后执行,在这 5s 期间,断点处是没有 this
的,也就是没有执行注入。
inject
useFactory
函数是可以接收参数的,其参数就是通过 inject
注入的
providers: [
PersonService,
{
provide: 'person_static_value',
useValue: {
name: '张三',
age: 20,
},
},
{
provide: 'person_factory',
// 注入了两个 token,分别是 person_static_value 和 PersonService
inject: ['person_static_value', PersonService],
useFactory: async (
person: { name: string; age: number },
personService: PersonService,
) => {
return {
personName: person.name,
hello: personService.findAll(),
};
},
},
],
useExisting
大概作用就是对一个已有的 token 起一个别名,比如将 A
起个别名 A1
,那么在使用 A1
作为 token 注入是,实际也是注入的 A
全局模块和生命周期
全局模块
当某些模块,比如 CommonService
本身就属于公用模块,但是每次在其它 Service 中使用时,都需要在 Module 中 imports
导入,数量多的话就较为繁琐,此时就可以把该模块设置为全局模块,使其在全局设置一次,即可所有模块共用。
比如 PersonService
需要使用 的方法,正常注入其它模块,需要以下步骤:
若是公共模块,每个模块都 imports 太麻烦了,此时可以把它声明为全局的
声明为全局模块
使用 @Global()
装饰器即可将模块声明为全局的,此时就不用 imports
就可以直接 @Inject
注入了。
@Global()
@Module({
controllers: [AnimalController],
providers: [AnimalService],
exports: [AnimalService],
})
但是全局模块尽量少使用,不然项目庞大之后,内部注入的全局模块很难找到来源
生命周期
详情可查看 Nest 中文网-生命周期事件,该章节强烈建议读文档
启动生命周期
启动时的生命周期有两个 onModuleInit
和 onApplicationBootstrap
- 首先会递归模块(Module),依次调用模块内的
controller
、provider
的onModuleInit
方法,然后再调用 module 的onModuleInit
方法 - 全部初始化完之后,再依次调用模块内的
controller
、provider
的onApplicationBootstrap
方法,然后调用 module 的onApplicationBootstrap
方法 - 然后监听网络端口
- Nest 程序正常运行
将 Person 模块的 controller
、service
、module
中都继承 onModuleInit
和 onApplicationBootstrap
Animal 模块操作同上图,
得到的打印结果是:
销毁生命周期
只有显示的使用 app.close()
才会触发销毁的生命周期,但 app.close()
只会触发销毁生命周期,不会终止 Node 进程
销毁时的生命周期有三个 onModuleDestroy
beforeApplicationShutdown
onApplicationShutdown
- 先调用每个模块的
controller
、provider
的onModuleDestroy
方法,然后调用 Module 的onModuleDestroy
方法。 - 之后再调用每个模块的
controller
、provider
的beforeApplicationShutdown
方法,然后调用 Module 的beforeApplicationShutdown
方法。 - 然后停止监听网络端口。
- 之后调用每个模块的
controller
、provider
的onApplicationShutdown
方法,然后调用 Module 的onApplicationShutdown
方法。 - 之后停止进程。
先让两个模块的 controller
、sevice
、module
继承 onModuleDestroy
beforeApplicationShutdown
onApplicationShutdown
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3000);
setTimeout(() => {
app.close(); // 显式销毁
}, 5000);
}
标签:PersonService,系列,providers,provide,基础,Module,person,Nestjs,模块
From: https://www.cnblogs.com/jsonq/p/18049416