从不同的模块注入 Nest.js 服务

在 Nest.js 中跨模块注入服务

在 Nest.js 框架中,跨不同模块注入服务需要遵循特定的步骤,以确保依赖注入机制的正确运作和模块的良好组织。 本文将使用两个示例模块,详细阐述如何导出服务并将其导入到另一个模块中使用。

创建 Nest.js 项目

首先,你需要在你的开发环境中安装 Nest.js 命令行工具(CLI)。 如果尚未安装,请使用以下命令进行安装:

 npm install -g @nestjs/cli

安装完成后,使用以下命令创建一个新的 Nest.js 项目:

 nest new <项目名称>

请将 <项目名称> 替换为你想要的项目名称。 执行此命令后,Nest.js CLI 将为你创建一个新的项目框架。

项目创建完成后,你的目录结构应该类似于下面的示例:

为了演示服务注入,我们将创建两个模块: module-amodule-b,并为它们分别生成相应的服务和控制器文件。

使用以下命令创建 module-a:

 nest generate module module-a

同样,创建 module-b:

 nest generate module module-b

接下来,为 module-a 创建服务和控制器:

 nest generate service module-a && nest generate controller module-a

同样,为 module-b 创建服务和控制器:

 nest generate service module-b && nest generate controller module-b

此时,你的项目目录结构应该包含 src/module-asrc/module-b 两个子目录,如下所示:

从模块 A 导出服务

要使 module-a 的服务(ModuleAService)能够被其他模块访问,你需要在 module-a.module.ts 文件中将其声明为导出项。 默认情况下,Nest.js CLI 不会自动生成 exports 数组。因此,你需要在 @Module 装饰器中手动添加它。 默认情况下生成的模块文件如下:

import { Module } from '@nestjs/common';
import { ModuleAService } from './module-a.service';
import { ModuleAController } from './module-a.controller';

@Module({
  providers: [ModuleAService],
  controllers: [ModuleAController],
})

export class ModuleAModule {}

修改 module-a.module.ts 文件,添加 exports 数组,并将 ModuleAService 添加到其中:

import { Module } from '@nestjs/common';
import { ModuleAService } from './module-a.service';
import { ModuleAController } from './module-a.controller';

@Module({
  providers: [ModuleAService],
  controllers: [ModuleAController],
  exports: [ModuleAService],
})

export class ModuleAModule {}

接下来,为了测试,在 module-a.service.ts 文件中添加一个简单的函数:

import { Injectable } from '@nestjs/common';

@Injectable()
export class ModuleAService {
  getHello(): string {
    return 'Hello from Module A!';
  }
}

这个函数返回一个字符串。 为了验证是否可以成功导入此服务,我们将在 module-b 中调用这个函数。

将服务导入模块 B

要将一个模块导入到另一个模块,你必须将其添加到接收模块的 imports 数组中。 在这种情况下,你需要将 module-a 添加到 module-b@Module 装饰器的 imports 数组中。 和以前一样,Nest.js CLI 不会自动生成 imports 数组,你需要手动创建它。

首先,你需要将父模块(module-a.module.ts)导入到接收模块(module-b.module.ts)中,创建 imports 数组,并将 ModuleAModule 添加到数组中:

import { Module } from '@nestjs/common';
import { ModuleBController } from './module-b.controller';
import { ModuleBService } from './module-b.service';
import { ModuleAModule } from '../module-a/module-a.module';

@Module({
  imports: [ModuleAModule],
  controllers: [ModuleBController],
  providers: [ModuleBService],
})

export class ModuleBModule {}

接下来,打开 module-b.service.ts 文件,从 @nestjs/common../module-a/module-a.service 导入 Inject 装饰器和 ModuleAService

import { Injectable, Inject } from '@nestjs/common';
import { ModuleAService } from '../module-a/module-a.service';

Inject 装饰器用于标记依赖注入的目标。

ModuleBService 类中,添加以下代码:

  @Inject(ModuleAService)
  private readonly moduleAService: ModuleAService;

这段代码允许你的 ModuleBService 访问 ModuleAService 中可用的方法。

你可以通过调用 ModuleAServicegetHello 方法来测试服务:

import { Injectable, Inject } from '@nestjs/common';
import { ModuleAService } from '../module-a/module-a.service';

@Injectable()
export class ModuleBService {
  @Inject(ModuleAService)
  private readonly moduleAService: ModuleAService;

  getHello(): string {
    return this.moduleAService.getHello();
  }
}

接着,打开 module-b.controller.ts 文件,并替换为以下代码:

import { Controller, Get } from '@nestjs/common';
import { ModuleBService } from './module-b.service';

@Controller('module-b')
export class ModuleBController {
  constructor(private readonly moduleBService: ModuleBService) {}

  @Get('/hello')
  getHello(): string {
    return this.moduleBService.getHello();
  }
}

这段代码为 getHello 函数设置了一个 HTTP GET 路由。

最后,使用 curl 向 localhost:3000/module-b/hello 发送一个 GET 请求。 终端应该打印出 “Hello from Module A!”。

你已经成功地将一个服务注入到了另一个模块中。 这在构建包含多个相互调用方法的模块的 API 时非常有用。

跨模块注入的优势

尽管直接从其他模块调用服务可能看起来更简单,但是长期来看,它会导致系统变得更加复杂、难以维护和扩展。

然而,跨模块注入鼓励代码的模块化和可重用性,使其更容易维护。 此外,它集中了依赖项、提高了可测试性,并支持可扩展的解耦架构。