手动实例化Nest.js providers的正确方法与运行时依赖注入实现疑问
问题核心原因
你当前的写法本质是手动实例化类,这种方式创建的实例不归Nest的IoC容器托管,自然不会触发自动依赖注入,所以必须手动传构造参数,不符合DI的设计规范。
推荐实现方案
你需要用Nest的自定义Provider能力实现动态选择数据库实例,所有依赖都由容器自动注入,完全不需要手动传参。
前提准备
首先给所有数据库实现类添加@Injectable()装饰器,让Nest可以识别为可注入对象:
import { Injectable } from '@nestjs/common'; @Injectable() export class JSONDatabase implements IDatabase { dbType = DatabaseType.JSON; constructor(logger: LoggerService, io: IOService) { logger.log(`Doing something...`) } } @Injectable() export class SQLDatabase implements IDatabase { // 你的SQL实现逻辑 }
场景1:启动时根据配置固定数据库类型(绝大多数场景适用)
这种场景下用useFactory类型的自定义Provider,在模块初始化时就根据配置生成对应实例:
步骤1:定义注入令牌
先定义一个唯一的注入令牌用于标识数据库服务:
export const DATABASE = Symbol('DATABASE');
步骤2:在模块中注册Provider
在你对应的业务Module的providers数组中添加以下配置:
@Module({ providers: [ CommonService, LoggerService, IOService, JSONDatabase, SQLDatabase, { provide: DATABASE, useFactory: ( common: CommonService, logger: LoggerService, jsonDb: JSONDatabase, sqlDb: SQLDatabase ): IDatabase => { const databaseType = common.serverConfig.dbType as DatabaseType; if (databaseType === DatabaseType.JSON) return jsonDb; if (databaseType === DatabaseType.SQL) return sqlDb; logger.error('Unknown database type.'); throw new Error('Invalid database type'); }, // 声明工厂函数需要注入的依赖 inject: [CommonService, LoggerService, JSONDatabase, SQLDatabase] } ] }) export class YourModule {}
步骤3:注入使用
在需要用到数据库的服务中直接注入即可,不需要再做类型判断:
import { Inject, Injectable } from '@nestjs/common'; @Injectable() export class DatabaseService { constructor(@Inject(DATABASE) private readonly db: IDatabase) { // 直接使用this.db即可,已经是对应类型的实例,所有依赖都完成注入 } }
场景2:运行时需要动态切换数据库类型
如果你的数据库类型需要在程序运行过程中动态切换,而非启动时固定,可以用ModuleRef直接从容器中获取已经实例化完成的对象:
import { Injectable, ModuleRef } from '@nestjs/common'; @Injectable() export class DatabaseService { constructor( private readonly common: CommonService, private readonly logger: LoggerService, private readonly moduleRef: ModuleRef ) { const databaseType = common.serverConfig.dbType as DatabaseType; if (databaseType === DatabaseType.JSON) { // 直接从容器中获取JSONDatabase实例,依赖已经自动注入完成 this.loadDatabase(this.moduleRef.get(JSONDatabase)); } else if (databaseType === DatabaseType.SQL) { this.loadDatabase(this.moduleRef.get(SQLDatabase)); } else { logger.error('Unknown database type.'); } } }
以上两种方式都可以实现你要的不需要手动传构造参数、依赖由Nest IoC自动注入单例的需求。
内容的提问来源于stack exchange,提问作者iced
相关产品推荐
相关产品推荐

