模块Modules是用@Module()装饰器来装饰的,@Module()装饰器提供了Nest用来组织应用程序结构的元数据。
每个应用程序至少有一个模块,即根模块。根模块是Nest构建应用程序图的起点,Nest使用内部数据结构来解决模块和提供程序之间的关系和依赖关系。虽然理论上很小的应用程序可能只有根模块,但这不是典型的情况。我们想强调,强烈建议将模块作为组织组件的有效方式。因此,对于大多数应用程序,生成的架构将使用多个模块,每个模块封装一组密切相关的功能。
@Module()装饰器需要传入一个对象,该对象的财产描述了该模块:
| 对象key | 对象内容 |
|---|---|
providers | 将由Nest注入器实例化并且至少可以在该模块中共享的提供程序 |
controllers | 该模块中定义的一组必须实例化的控制器 |
imports | 导出此模块中所需提供程序的导入模块列表 |
exports | 此模块提供的providers子集,应在导入此模块的其他模块中可用 |
模块默认封装providers,因此,您可以将从模块导出的providers视为模块的公共接口或API。
功能模块
CatsController和CatsService属于相同的应用程序。因为他们的关系紧密,所以把他们放在同一个功能模块里面是比较合理的。Modules是用来组织代码之间的关系,保持代码啊的组织并确立清晰的边界。这可以帮助我们管理复杂的代码,并遵循SOLID原则进行开发。
CatsModule的内容:
import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
@Module({
controllers: [CatsController],
providers: [CatsService]
})
export class CatsModule {}
我们在文件cats.module.ts里定义了一个类CatsModule,并且把和这个模块相关的所有东西都放到了cats文件夹。最后必须把这个模块放到根模块(AppModule,在app.module.ts里面定义)的imports数组里面。
import { Module } from '@nestjs/common';
import { CatsModule } from './cats/cats.module';
@Module({
imports: [CatsModule],
controllers: [],
providers: [],
})
export class AppModule {}
共享模块
在Nest里,Modules都是单例的,因此可以在多个模块之间分享同一个实例。
每一个Modules都会自动成为一个共享模块。一旦被创建其他任何模块都能重复使用。假设我们想分享CatsService给其他的多个Modules。因此需要将CatsService加到模块的exports数组里面
import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
@Module({
controllers: [CatsController],
providers: [CatsService],
// 提供模块给其他模块分享
exports: [CatsService]
})
export class CatsModule {}
这样任何一个Modules只要在imports数组里面导入了CatsModule,都可以直接访问CatsService共享实例。
模块重新导出
如上所述,模块可以导出其内部提供程序。此外,他们还可以重新导出导入的模块。在下面的示例中,CommonModule既可以导入到CoreModule中,也可以从CoreModules中导出,从而使其可用于导入此模块的其他模块。
import { Module } from '@nestjs/common';
import { CommonModule } from 'src/common/common.module';
@Module({
imports: [CommonModule],
exports: [CommonModule],
})
export class CoreModule {}s
依赖注入
Modules里面也可以注入providers(一些配置模块,帮助模块):
import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
@Module({
controllers: [CatsController],
providers: [CatsService],
// 提供模块给其他模块分享
exports: [CatsService]
})
export class CatsModule {
// 注入Service
constructor(private catsService: CatsService) {}
}
然而,他们自己不能注入到其他模块中,这样会引起循环依赖。
全局模块
如果您想在任何地方都导入一个相同的模块,在所有的地方添加import是比较不恰当的。
当您想让这个模块全局都能使用,可以使用@Global()装饰器。
import { Module,Global } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
// 全局装饰器
@Global()
@Module({
controllers: [CatsController],
providers: [CatsService],
// 提供模块给其他模块分享
exports: [CatsService]
})
export class CatsModule {
// 注入Service
constructor(private catsService: CatsService) {}
}
@Global()修饰符使模块具有全局作用域。全局模块只能注册一次,通常由根模块或核心模块注册。在上面的示例中,CatsService提供程序将无处不在,希望注入服务的模块不需要在其导入数组中导入CatsModule。
注意:全局装饰器不能乱用,最佳的使用方式还是应该通过`Imports`的方式,一般日志,数据库这一类的模块可以使用全局模块
动态模块
Nest模块系统包括一个称为动态模块的强大功能。此功能使您能够轻松创建可自定义的模块,这些模块可以动态注册和配置提供程序。
import { Module, DynamicModule } from '@nestjs/common';
import { createDatabaseProviders } from './database.providers';
import { Connection } from './connection.provider';
@Module({
providers: [Connection],
})
export class DatabaseModule {
static forRoot(entities = [], options?): DynamicModule {
const providers = createDatabaseProviders(options, entities);
return {
module: DatabaseModule,
providers: providers,
exports: providers,
};
}
}
提示:forRoot()方法可以同步或异步(即通过Promise)返回动态模块。
该模块默认定义ConnectionProvider(在@module()装饰器元数据中),但根据传递给forRoot()法的实体和选项对象,它还公开了一组提供程序,例如存储库。请注意,动态模块返回的模块扩展(而不是覆盖)了@module()修饰符中定义的基本模块元数据。这就是从模块中导出静态声明的Connection提供程序和动态生成的存储库提供程序的方式。
如果要在全局范围中注册动态模块,请将全局属性设置为true。
{
// 全局注册
global: true,
module: DatabaseModule,
providers: providers,
exports: providers,
}
可以以下列方式导入和配置DatabaseModule:
import { Module } from '@nestjs/common';
import { DatabaseModule } from './database/database.module';
import { User } from './users/entities/user.entity';
@Module({
imports: [DatabaseModule.forRoot([User])],
controllers: [],
providers: [],
exports:[],
})
export class AppModule {}
如果您想反过来重新导出动态模块,可以省略exports数组中的forRoot()方法调用:
@Module({
imports: [DatabaseModule.forRoot([User]),CatsModule, CoreModule, CommonModule],
controllers: [],
providers: [],
exports:[DatabaseModule]
})
export class AppModule {}