前边我们说了Controller和Provider,都是在appModule直接引入的,这就是我们的根模块,是构建应用图的起点。我们还会有其他的各种模块,每个模块封装了一组密切相关的功能。
@Module装饰器接收一个对象,对象的属性描述了模块:
providers - 由Nest注入容器实例化的提供者,可以在当前模块内共享
controllers - 此模块定义的一组控制器
imports - 导入的模块列表,被导入的模块中导出当前模块中所需要的providers
exports - 导出的providers, 是当前模块的providers的子集,可以在其他导入当前模块的模块中使用(也可以重新导出导入的模块,这种情况下就不是providers的子集了)
关于providers和controllers,我们前边已经讲过了,而imports和exports就是与模块相关的内容了。
本章节我们关注模块的导入,也就是imports的内容
前置准备
我们之前开发了user.service和user.controller,现在我们新建一个user.module文件,将user功能封装到一个模块中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import { Module } from "./@nestjs/common"; import { UseValueService } from "./use-value.service"; import { UserController } from "./user.controller"; import { UserService } from "./user.service";
@Module({ controllers: [UserController], providers: [ UserService, { provide: 'StringToken', useValue: new UseValueService() }, ], exports: [ UserService, 'StringToken' ] }) export class UserModule {}
|
在app.module中,我们也进行调整,只要导入user.module就可以了
1 2 3 4 5 6 7 8 9 10 11
| import { Module } from './@nestjs/common'; import { AppController } from './app.controller'; import { UserModule } from './user.module'; @Module({ controllers: [AppController], providers: [], imports: [UserModule] }) export class AppModule {}
|
接下来我们要开始源码的部分了。
源码实现
首先完善一下@Module装饰器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| import 'reflect-metadata'
interface ModuleMetadata { controllers?: Function[] providers?: any[] imports?: any[] exports?: any[] }
export function Module(metadata: ModuleMetadata): ClassDecorator { return (target: Function) => { Reflect.defineMetadata('controllers', metadata.controllers, target) Reflect.defineMetadata('providers', metadata.providers, target) Reflect.defineMetadata('imports', metadata.imports, target) Reflect.defineMetadata('exports', metadata.exports, target) } }
|
之前我们在nest-application中,调用initProviders注册了所有的提供者,现在引入了模块的概念,要复杂的多,所以我们重写initProviders的流程,并添加了一个addProvider方法实现原有的注册功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| initProviders() { const imports = Reflect.getMetadata('imports', this.module) ?? [] for (const importModule of imports) { const importedProviders = Reflect.getMetadata('providers', importModule) ?? [] for (const provider of importedProviders) { this.addProvider(provider) } } const providers = Reflect.getMetadata('providers', this.module) ?? [] for (const provider of providers) { this.addProvider(provider) } } addProvider(provider) { const injectToken = provider?.provide ?? provider if (this.providers.has(injectToken)) { return } if (provider.provide && provider.useClass) { const dependencies = this.resolveDependencies(provider.useClass) const instance = new provider.useClass(...dependencies) this.providers.set(provider.provide, instance) } else if (provider.provide && provider.useValue) { this.providers.set(provider.provide, provider.useValue) } else if (provider.provide && provider.useFactory) { const inject = provider.inject ?? [].map(token => { return this.providers.get(token) ?? token })
this.providers.set(provider.provide, provider.useFactory(...inject)) } else { const dependencies = this.resolveDependencies(provider) this.providers.set(provider, new provider(...dependencies)) } }
|
现在只是以AppModule为根模块,将AppModule以及所有导入模块的provider注册了,功能实现并不完全,比如:
- 导入的模块可能会导入其他模块,没有实现递归的模块依赖关系分析
- 导入的模块的
providers可能只导出了一部分,没有全量导出,但是我们进行的全量注册
- 只解析了根模块的
controller,其他模块注册的路由暂无法使用
provider没有实现模块间的隔离
exports还没有解析
本节我们只实现导入功能,这里说的这些功能等到后边再来实现