菜单

模块系统

相关源文件

介绍

NestJS 的模块系统提供了一种组织应用程序组件和管理依赖关系的结构化方式。它是组织 NestJS 应用程序代码的基础构建块。本文档涵盖了模块架构、注册过程以及模块如何通过依赖注入系统进行交互。有关整体依赖注入系统的信息,请参阅 2.1

NestJS 中的模块封装了相关代码,例如提供者(服务、存储库、工厂等)和控制器,这有助于开发人员保持清晰的应用程序结构以及应用程序不同部分之间的清晰边界。

来源: packages/core/injector/module.ts44-675

模块结构

NestJS 中的模块是一个带有所装饰的类 @Module()。模块装饰器接受一个描述模块组件的元数据对象。

模块类本身维护着这些组件的集合。

来源: packages/core/injector/module.ts44-176

模块组件

提供者

提供者是您的应用程序所需的任何可注入类或值,例如服务、存储库、工厂等。模块类使用注入标记作为键,将提供者存储在 Map 中。

来源: packages/core/injector/module.ts244-285

控制器

控制器处理传入的请求并将响应返回给客户端。它们也作为 InstanceWrappers 存储在 Map 中。

来源: packages/core/injector/module.ts503-519

导入

导入定义了此模块所依赖的其他模块。导入存储为模块实例的 Set。

来源: packages/core/injector/module.ts530-532

导出

导出定义了此模块中的哪些提供者应提供给导入此模块的其他模块。导出存储为注入标记的 Set。

来源: packages/core/injector/module.ts454-469

模块注册

模块在应用程序引导过程中注册。 DependenciesScanner 负责扫描模块及其依赖项。

来源: packages/core/scanner.ts75-111

模块扫描过程

模块扫描过程涉及

  1. 注册根模块
  2. 递归扫描导入的模块
  3. 从每个模块的导入、提供者、控制器和导出中反射元数据
  4. 将这些组件添加到模块

来源: packages/core/scanner.ts106-174

模块类型

功能模块

功能模块是标准模块,按特定功能区域组织应用程序代码。它们包含与应用程序特定功能相关的提供者和控制器。

全局模块

全局模块无需导入即可在应用程序的所有其他模块中使用。这是通过在模块上设置 isGlobal 标志来实现的。

容器使用此标志将全局模块绑定到所有其他模块。

来源: packages/core/injector/module.ts95-101 packages/core/scanner.ts103

动态模块

动态模块是可以在导入时进行自定义的模块。它们是使用返回 DynamicModule 对象的工厂方法创建的。

在扫描模块时,动态模块的处理方式不同。

来源: packages/core/scanner.ts716-720 packages/core/scanner.ts131-144

模块依赖解析

模块系统的关键方面之一是如何解析模块之间的依赖关系。当一个模块导入另一个模块时,它可以访问该模块导出的提供者。

导入解析

当一个模块导入另一个模块时,DependenciesScanner 会将导入的模块添加到导入模块的 imports 集合中。

来源: packages/core/scanner.ts418-426

提供者解析

Injector 负责解析提供者之间的依赖关系。当实例化提供者时,其依赖项会通过模块图进行解析。

来源: packages/core/injector/injector.ts109-186 packages/core/injector/injector.ts447-475

导出验证

Module 类会验证导出的提供者要么由模块本身提供,要么从其他模块导入。

来源: packages/core/injector/module.ts485-501

模块距离和拓扑

NestJS 中的模块构成了一个图结构。为了优化依赖解析,NestJS 使用拓扑树计算每个模块与根模块的“距离”。

此距离计算有助于优化依赖解析过程。

来源: packages/core/scanner.ts397-416 packages/core/injector/topology-tree/topology-tree.ts1-57

模块初始化

在应用程序引导过程中,InstanceLoader 负责初始化每个模块中的所有提供者和控制器。这发生在所有模块都已注册并扫描其依赖项之后。

高级模块模式

前向引用

前向引用允许模块之间存在循环依赖。 forwardRef() 函数返回一个特殊对象,模块系统可以处理该对象。

来源: packages/core/scanner.ts421-423

模块引用

每个模块都可以访问 ModuleRef,它可用于从模块中检索提供者。

这允许在运行时动态访问提供者。

来源: packages/core/injector/module.ts597-647

自定义提供者类型

NestJS 支持各种类型的自定义提供者:

  1. 值提供者 - 提供静态值
  2. 类提供者 - 指定要实例化的类
  3. 工厂提供者 - 使用工厂函数创建实例
  4. 现有提供者 - 使用现有提供者(别名)

来源: packages/core/injector/module.ts305-324

模块注册表(容器)

NestContainer 作为应用程序中所有模块的注册表。它提供添加、替换和检索模块的方法。

来源: packages/core/injector/container.ts31-693

总结

NestJS 模块系统为组织应用程序代码和管理依赖关系提供了一个强大的基础。通过将相关代码封装在模块中,并在应用程序的不同部分之间建立清晰的界限,它提高了可维护性和可伸缩性。主要功能包括:

  1. 通过 @Module() 装饰器进行结构化组织
  2. 灵活的组件注册(providers、controllers、imports、exports)
  3. 通过模块图进行依赖解析
  4. 支持不同的模块类型(feature、global、dynamic)
  5. 如前向引用和模块引用的高级模式
  6. 自定义 provider 注册

理解模块系统对于构建结构良好的 NestJS 应用程序至关重要。