NestJS05-Modules

1,705 阅读5分钟

模块Modules是用@Module()装饰器来装饰的,@Module()装饰器提供了Nest用来组织应用程序结构的元数据。

每个应用程序至少有一个模块,即根模块。根模块是Nest构建应用程序图的起点,Nest使用内部数据结构来解决模块和提供程序之间的关系和依赖关系。虽然理论上很小的应用程序可能只有根模块,但这不是典型的情况。我们想强调,强烈建议将模块作为组织组件的有效方式。因此,对于大多数应用程序,生成的架构将使用多个模块,每个模块封装一组密切相关的功能。

@Module()装饰器需要传入一个对象,该对象的财产描述了该模块:

对象key对象内容
providers将由Nest注入器实例化并且至少可以在该模块中共享的提供程序
controllers该模块中定义的一组必须实例化的控制器
imports导出此模块中所需提供程序的导入模块列表
exports此模块提供的providers子集,应在导入此模块的其他模块中可用

模块默认封装providers,因此,您可以将从模块导出的providers视为模块的公共接口或API。

功能模块

CatsControllerCatsService属于相同的应用程序。因为他们的关系紧密,所以把他们放在同一个功能模块里面是比较合理的。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都是单例的,因此可以在多个模块之间分享同一个实例。

未命名文件.png

每一个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 {}

代码地址

代码