神光《Nest 通关秘籍》学习总结-深入理解Provider如何注入对象
最近在学习神光大神的《Nest通关秘籍》,该小册主要包含下面这些内容:
想购买的可以点击《传送门》。
接下来的日子里,我将更新一系列的学习笔记。感兴趣的可以关注我的专栏《Nest 通关秘籍》学习总结。
特别申明:本系列文章已经经过作者本人的允许。 大家也不要想着白嫖,我的笔记只是个人边学习边记录的,不是很完整,大家想要深入学习还是要自己去购买原版小册。
本章我们来学习nest中的如何使用provider注入对象。
provider 一般都是用 @Injectable 修饰的 class:
// app.service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
getHello(): string {
return 'Hello World!';
}
}
然后在 Module 的 providers 里声明:
// app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [],
controllers: [AppController],
providers: [
AppService
],
})
export class AppModule {}
Provider的完整的写法是这样的:
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [],
controllers: [AppController],
providers: [
{
provide: AppService,
useClass: AppService,
},
],
})
export class AppModule {}
通过 provide 指定注入的 token,通过 useClass 指定注入的对象的类,Nest 会自动对它做实例化再注入。
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
}
除了使用构造器注入,还可以使用属性的方式注入:
import { Controller, Get, Inject } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
@Inject(AppService)
private readonly appService: AppService;
@Get()
getHello(): string {
return this.appService.getHello();
}
}
如果provide
是一个字符串:
...
@Module({
imports: [],
controllers: [AppController],
providers: [
{
provide: 'app_service',
useClass: AppService,
},
],
})
...
在注入的时候,就需要使用 @Inject
手动指定注入对象的 provide
了
...
@Controller()
export class AppController {
@Inject('app_service')
private readonly appService: AppService;
@Get()
getHello(): string {
return this.appService.getHello();
}
}
// or
...
@Controller()
export class AppController {
constructor(@Inject('app_service') private readonly appService: AppService) {}
@Get()
getHello(): string {
return this.appService.getHello();
}
}
一般我们都是直接使用class的方式去注入,方便简洁。
我们还可以在Provider里面使用useValue
注入一个值:
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [],
controllers: [AppController],
providers: [
{
provide: 'app_service',
useClass: AppService,
},
{
provide: 'person',
useValue: {
name: 'xiumubai',
age: 18,
},
},
],
})
export class AppModule {}
然后在对象里注入它:
import { Controller, Get, Inject } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(
@Inject('app_service') private readonly appService: AppService,
@Inject('person')
private readonly person: { name: string; age: number },
) {}
@Get()
getHello(): string {
console.log(this.person);
return this.appService.getHello();
}
}
使用断点调试,可以看到值:
使用useFactory
可以动态的来动态创建一个对象:
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [],
controllers: [AppController],
providers: [
{
provide: 'app_service',
useClass: AppService,
},
{
provide: 'person',
useValue: {
name: 'xiumubai',
age: 18,
},
},
{
provide: 'person2',
useFactory() {
return {
name: '朽木白',
age: 40,
};
},
},
],
})
export class AppModule {}
import { Controller, Get, Inject } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(
@Inject('app_service') private readonly appService: AppService,
@Inject('person')
private readonly person: { name: string; age: number },
@Inject('person2')
private readonly person2: { name: string; age: number },
) {}
@Get()
getHello(): string {
console.log(this.person);
console.log(this.person2);
return this.appService.getHello();
}
}
还可以使用动态参数注入:
...
{
provide: 'person3',
useFactory(person: { name: string }, appService: AppService) {
return {
name: person.name,
desc: appService.getHello(),
};
},
inject: ['person', 'app_service'],
},
...
import { Controller, Get, Inject } from '@nestjs/common';
import { AppService } from './app.service';
@Controller()
export class AppController {
constructor(
@Inject('app_service') private readonly appService: AppService,
@Inject('person')
private readonly person: { name: string; age: number },
@Inject('person2')
private readonly person2: { name: string; age: number },
@Inject('person3')
private readonly person3: { name: string; desc: string },
) {}
@Get()
getHello(): string {
console.log(this.person);
console.log(this.person2);
console.log(this.person3);
return this.appService.getHello();
}
}
useFactory
还支持异步的使用:
{
provide: 'person3',
async useFactory(person: { name: string }, appService: AppService) {
await new Promise((resolve) => {
setTimeout(resolve, 3000);
});
return {
name: person.name,
desc: appService.getHello(),
};
},
inject: ['person', 'app_service'],
},
provider 还可以通过 useExisting 来指定别名,这里就是给 person2 的 token 的 provider 起个新的 token 叫做 person4。
{
provide: 'pserson4',
useExisting: 'person2',
},
总结:
- provider 是通过 @Injectable 声明,然后在 @Module 的 providers 数组里注册的 class。
- 默认的 token 就是 class,这样不用使用 @Inject 来指定注入的 token。
- 但也可以用字符串类型的 token,不过注入的时候要用 @Inject 单独指定。
- 除了可以用 useClass 指定注入的 class,还可以用 useValue 直接指定注入的对象。
- 如果想动态生成对象,可以使用 useFactory,它的参数也注入 IOC 容器中的对象,然后动态返回 provider 的对象。
- 如果想起别名,可以用 usExisting 给已有的 token,指定一个新 token。
- 灵活运用这些 provider 类型,就可以利用 Nest 的 IOC 容器中注入任何对象。
转载自:https://juejin.cn/post/7242198986261856317