【NestJS】依赖注入(DI) 的模块系统、`imports`、`@Module`、`providers` 之间的关系彻底搞清楚
1️⃣ @Module() 的作用
在 NestJS 中,模块 (Module) 是组织代码的基本单位。它有四大核心属性:
| 属性 | 作用 |
|---|---|
providers | 定义当前模块提供的服务(可以被注入的类、值、工厂等) |
controllers | 定义当前模块的控制器(接收请求、调用服务) |
imports | 导入其他模块,使得它们导出的 providers 可被当前模块使用 |
exports | 将当前模块中的 providers 暴露给被导入模块使用 |
简单理解:
- 模块 = 容器,负责收集 provider、控制器、导入的依赖。
- 每个模块内部的 provider 默认只能在模块内部使用,除非用
exports暴露。 - 模块之间通过
imports和exports建立依赖关系。
2️⃣ providers 的作用
providers 就是 模块可注入对象的清单。
支持的类型:
- 类(最常用):
@Injectable()
export class UserService {}
在模块中注册:
@Module({providers: [UserService],
})
export class UserModule {}
- 值(useValue):
@Module({providers: [{ provide: 'API_KEY', useValue: '123456' },],
})
- 工厂函数(useFactory):
@Module({providers: [{provide: DatabaseService,useFactory: () => new DatabaseService(process.env.DB_URL),},],
})
- 替代实现(useClass):
@Module({providers: [{ provide: Logger, useClass: FileLogger },],
})
所有 provider 最终都会注册到模块的 IoC 容器 中,供构造函数注入使用。
3️⃣ imports 的作用
imports 是 模块间依赖的桥梁。
- 当一个模块需要使用其他模块的 provider 时,就要通过
imports导入那个模块。 - 被导入模块必须通过
exports将需要共享的 provider 暴露。
示例:
// database.module.ts
@Module({providers: [DatabaseService],exports: [DatabaseService], // 暴露给其他模块
})
export class DatabaseModule {}// user.module.ts
@Module({imports: [DatabaseModule], // 导入 DatabaseModuleproviders: [UserService], // UserService 依赖 DatabaseService
})
export class UserModule {}
Nest 启动时,容器会:
- 加载
UserModule; - 发现它导入了
DatabaseModule; - 从
DatabaseModule.exports中注册DatabaseService; - UserService 的构造函数依赖
DatabaseService,容器自动注入。
总结:imports + exports = 模块间依赖共享机制。
4️⃣ provider 和模块的关联
关系可理解为:
@Module({imports: [...], // 导入模块,获取它们 exports 的 providersproviders: [...], // 当前模块自己的 providerscontrollers: [...], // 当前模块控制器exports: [...] // 将当前模块的 providers 暴露给其他模块
})
依赖注入流程:
- 容器扫描模块的
providers→ 注册到模块容器。 - 容器扫描模块的
imports→ 取到导入模块的exports→ 合并到当前模块容器。 - 当控制器或 provider 需要依赖时,容器从模块容器中查找 provider 实例。
5️⃣ 总结
@Module()= 容器 + 组织模块结构providers= 当前模块提供的可注入服务imports= 导入其他模块的导出 providersexports= 暴露当前模块的 providers 给其他模块- DI 的魔力就在于:模块之间解耦,provider 生命周期由容器统一管理,控制器只关注业务逻辑
