在 Nest.js 中跨模块注入服务
在 Nest.js 框架中,跨不同模块注入服务需要遵循特定的步骤,以确保依赖注入机制的正确运作和模块的良好组织。 本文将使用两个示例模块,详细阐述如何导出服务并将其导入到另一个模块中使用。
创建 Nest.js 项目
首先,你需要在你的开发环境中安装 Nest.js 命令行工具(CLI)。 如果尚未安装,请使用以下命令进行安装:
npm install -g @nestjs/cli
安装完成后,使用以下命令创建一个新的 Nest.js 项目:
nest new <项目名称>
请将 <项目名称>
替换为你想要的项目名称。 执行此命令后,Nest.js CLI 将为你创建一个新的项目框架。
项目创建完成后,你的目录结构应该类似于下面的示例:
为了演示服务注入,我们将创建两个模块: module-a
和 module-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-a
和 src/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
中可用的方法。
你可以通过调用 ModuleAService
的 getHello
方法来测试服务:
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 时非常有用。
跨模块注入的优势
尽管直接从其他模块调用服务可能看起来更简单,但是长期来看,它会导致系统变得更加复杂、难以维护和扩展。
然而,跨模块注入鼓励代码的模块化和可重用性,使其更容易维护。 此外,它集中了依赖项、提高了可测试性,并支持可扩展的解耦架构。