-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5fe8345
commit fda5a9a
Showing
2 changed files
with
291 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,290 @@ | ||
[源码](https://github.com/thinkasany/nestjs-course-code) | ||
|
||
[掘金](https://juejin.cn/book/7226988578700525605/section/7227379507152781349) | ||
|
||
> 这一章主要是讲的如何在DI里为依赖提供注入 | ||
> | ||
> Nest 实现了 IOC 容器,会从入口模块开始扫描,分析 Module 之间的引用关系,对象之间的依赖关系,自动把 provider 注入到目标对象。 | ||
``` | ||
Provide 注入写法: | ||
1. 简写方式 | ||
2.useValue | ||
1. useClass | ||
4.useExisting | ||
5.useFactory | ||
``` | ||
|
||
# provider 一般都是用 @Injectable 修饰的 class: | ||
|
||
``` | ||
@Injectable() | ||
export class AppService { | ||
getHello(): string { | ||
return 'Hello World!'; | ||
} | ||
} | ||
``` | ||
|
||
在 Module 的 providers 里声明: | ||
|
||
``` | ||
@Module({ | ||
imports: [], | ||
controllers: [AppController], | ||
providers: [AppService] | ||
``` | ||
|
||
其实这是一种简写,完整的写法是这样的: | ||
|
||
``` | ||
providers: [ | ||
{ | ||
provide: AppService, | ||
useClass: AppService, | ||
}, | ||
], | ||
``` | ||
|
||
# 通过 provide 指定注入的 token,通过 useClass 指定注入的对象的类,Nest 会自动对它做实例化再注入。 | ||
|
||
``` | ||
@Controller() | ||
export class AppController { | ||
constructor(private readonly appService: AppService) {} | ||
@Get() | ||
getHello(): string { | ||
return this.appService.getHello(); | ||
} | ||
} | ||
``` | ||
|
||
# 如果不想用构造器注入,也可以属性注入: | ||
|
||
``` | ||
@Controller() | ||
export class AppController { | ||
@Inject(AppService) | ||
private readonly appService: AppService; | ||
@Get() | ||
getHello(): string { | ||
return this.appService.getHello(); | ||
} | ||
} | ||
``` | ||
|
||
通过 @Inject 指定注入的 provider 的 token 即可。 | ||
|
||
# 当然,这个 token 也可以是字符串: | ||
|
||
``` | ||
providers: [ | ||
{ | ||
provide: 'app_service', | ||
useClass: AppService, | ||
}, | ||
], | ||
``` | ||
|
||
如果 token 是字符串的话,注入的时候就要用 @Inject 手动指定注入对象的 token 了: | ||
|
||
``` | ||
@Controller() | ||
export class AppController { | ||
@Inject('app_service') | ||
private readonly appService: AppService; | ||
@Get() | ||
getHello(): string { | ||
return this.appService.getHello(); | ||
} | ||
} | ||
``` | ||
|
||
相比之下,用 class 做 token 可以省去 @Inject,比较简便。 | ||
|
||
# 除了指定 class 外,还可以直接指定一个值,让 IOC 容器来注入。 | ||
|
||
``` | ||
providers: [ | ||
AppService, | ||
{ | ||
provide: 'person', | ||
useValue: { | ||
name: 'aaa', | ||
age: 20, | ||
}, | ||
}, | ||
], | ||
``` | ||
|
||
使用 provide 指定 token,使用 useValue 指定值。 | ||
|
||
然后在对象里注入它: | ||
|
||
``` | ||
@Controller() | ||
export class AppController { | ||
@Inject(AppService) | ||
private readonly appService: AppService; | ||
@Inject('person') | ||
private readonly person: { name: string; age: number }; | ||
@Get() | ||
getHello(): string { | ||
console.log(this.person); | ||
return this.appService.getHello(); | ||
} | ||
} | ||
``` | ||
|
||
# provider 的值可能是动态产生的,Nest 也同样支持: | ||
|
||
``` | ||
providers: [ | ||
AppService, | ||
{ | ||
provide: 'person2', | ||
useFactory() { | ||
return { | ||
name: 'bbb', | ||
desc: 'cccc', | ||
}; | ||
}, | ||
}, | ||
], | ||
``` | ||
|
||
使用 useFactory 来动态创建一个对象。 | ||
|
||
在对象里注入: | ||
|
||
``` | ||
@Controller() | ||
export class AppController { | ||
@Inject(AppService) | ||
private readonly appService: AppService; | ||
@Inject('person2') | ||
private readonly person2: { name: string; desc: string }; | ||
@Get() | ||
getHello(): string { | ||
console.log(this.person2); | ||
return this.appService.getHello(); | ||
} | ||
} | ||
``` | ||
|
||
这个 useFactory 也是支持参数的注入的: | ||
|
||
``` | ||
providers: [ | ||
AppService, | ||
{ | ||
provide: 'person', | ||
useValue: { | ||
name: 'aaa', | ||
age: 20, | ||
}, | ||
}, | ||
{ | ||
provide: 'person3', | ||
useFactory(person: { name: string }, appService: AppService) { | ||
return { | ||
name: person.name, | ||
desc: appService.getHello(), | ||
}; | ||
}, | ||
inject: ['person', AppService], | ||
}, | ||
], | ||
``` | ||
|
||
``` | ||
@Controller() | ||
export class AppController { | ||
@Inject(AppService) | ||
private readonly appService: AppService; | ||
@Inject('person') | ||
private readonly person: { name: string; age: number }; | ||
@Inject('person3') | ||
private readonly person3: { name: string; desc: string }; | ||
@Get() | ||
getHello(): string { | ||
console.log(this.person3); | ||
return this.appService.getHello(); | ||
} | ||
} | ||
``` | ||
|
||
``` | ||
ication successfully started +1ms | ||
{ name: 'aaa', desc: 'Hello World!' } | ||
``` | ||
|
||
通过 inject 声明了两个 token,一个是字符串 token 的 person,一个是 class token 的 AppService。 | ||
|
||
在调用 useFactory 方法的时候,Nest 就会注入这两个对象: | ||
|
||
# useFactory 支持异步: | ||
|
||
``` | ||
providers: [ | ||
AppService, | ||
{ | ||
provide: 'person5', | ||
async useFactory() { | ||
await new Promise((resolve) => { | ||
setTimeout(resolve, 5000); | ||
}); | ||
return { | ||
name: 'bbb', | ||
desc: 'cccc', | ||
}; | ||
}, | ||
}, | ||
], | ||
``` | ||
|
||
# 此外,provider 还可以通过 useExisting 来指定别名: | ||
|
||
``` | ||
{ | ||
provide: 'person4', | ||
useExisting: 'person2', | ||
}, | ||
``` | ||
|
||
这里就是给 person2 的 token 的 provider 起个新的 token 叫做 person4。 | ||
|
||
然后就可以用新 token 来注入了 | ||
|
||
这些自定义 provider 的方式里,最常用的是 useClass,不过我们一般会用简写,也就是直接指定 class。 | ||
|
||
useClass 的方式由 IOC 容器负责实例化,我们也可以用 useValue、useFactory 直接指定对象。 | ||
|
||
useExisting 只是用来起别名的,有的场景下会用到。 | ||
|
||
比如 @nestjs/typeorm 里就用到了 useValue、useFactory、useExisting | ||
|
||
用 useFactory 根据传入的 options | ||
[动态创建数据库连接对象:](https://github.com/nestjs/typeorm/blob/153da09a384fdbf797b66e4500b69a72a7a47b78/lib/typeorm-core.module.ts#L83-L101) | ||
|
||
用 useExisting 给 DataSource 起了一个 Connection | ||
|
||
# 总结 | ||
|
||
一般情况下,provider 是通过 @Injectable 声明,然后在 @Module 的 providers 数组里注册的 class。 | ||
|
||
默认的 token 就是 class,这样不用使用 @Inject 来指定注入的 token。 | ||
|
||
但也可以用字符串类型的 token,不过注入的时候要用 @Inject 单独指定。 | ||
|
||
除了可以用 useClass 指定注入的 class,还可以用 useValue 直接指定注入的对象。 | ||
|
||
如果想动态生成对象,可以使用 useFactory,它的参数也注入 IOC 容器中的对象,然后动态返回 provider 的对象。 | ||
|
||
如果想起别名,可以用 useExisting 给已有的 token,指定一个新 token。 | ||
|
||
灵活运用这些 provider 类型,就可以利用 Nest 的 IOC 容器中注入任何对象。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters