虽然应尽可能避免循环依赖,但您不能总是这样做。在这种情况下,Nest 可以通过两种方式解决提供程序之间的循环依赖。在本章中,我们描述了使用前向引用作为一种技术,并使用ModuleRef类从 DI 容器中检索提供程序实例作为另一种技术。
我们还描述了如何解决模块之间的循环依赖。
使用barrel 文件
/index.ts 文件对导入进行分组时也可能导致循环依赖。当涉及模块/提供程序类时,应省略 barrel 文件。例如,在导入与 barrel 文件位于同一目录中的文件时不应使用 barrel 文件,即 cats/cats.controller
不应导入 cats
来导入 cats/cats.service
文件。有关更多详细信息,另请参阅 此 github 问题。
前向引用
前向引用 允许 Nest 使用 forwardRef()
实用函数引用尚未定义的类。例如,如果 CatsService
和 CommonService
相互依赖,则关系的双方都可以使用 @Inject()
和 forwardRef()
实用工具来解决循环依赖。否则 Nest 将不会实例化它们,因为所有必要的元数据都不可用。以下是一个例子:
// cats.service
@Injectable()
export class CatsService {
constructor(
@Inject(forwardRef(() => CommonService))
private commonService: CommonService,
) {}
}
forwardRef()
函数从 @nestjs/common
包导入。
这涵盖了关系的一侧。现在让我们对 CommonService
执行相同操作:
@Injectable()
export class CommonService {
constructor(
@Inject(forwardRef(() => CatsService))
private catsService: CatsService,
) {}
}
@Injectable()
@Dependencies(forwardRef(() => CatsService))
export class CommonService {
constructor(catsService) {
this.catsService = catsService;
}
}
实例化的顺序不确定。请确保您的代码不依赖于首先调用哪个构造函数。循环依赖关系依赖于具有 Scope.REQUEST
的提供程序可能会导致未定义的依赖关系。更多信息可在此处获得此处
ModuleRef 类替代方案
使用 forwardRef()
的替代方法是重构代码并使用 ModuleRef
类检索(否则)循环关系一侧的提供程序。了解有关 ModuleRef
实用程序类的更多信息此处。
模块前向引用
为了解决模块之间的循环依赖关系,请在模块关联的两侧使用相同的 forwardRef()
实用程序函数。例如:
@Module({
imports: [forwardRef(() => CatsModule)],
})
export class CommonModule {}
这涵盖了关系的一方面。现在让我们对CatsModule
进行同样的操作:
@Module({
imports: [forwardRef(() => CommonModule)],
})
export class CatsModule {}