手动实例化 Nest.js 提供程序的正确方法
Proper way to manually instantiate Nest.js providers
我想我可能误解了 Nest.js 的 IoC 容器,或者整个 DI。
我有一个 class、JSONDatabase
,我想根据一些配置值(可以是 JSON 或 SQL)实例化自己。
我的 DatabaseService
提供商:
constructor(common: CommonService, logger: LoggerService) {
// eslint-disable-next-line prettier/prettier
const databaseType: DatabaseType = common.serverConfig.dbType as DatabaseType;
if (databaseType === DatabaseType.JSON) {
this.loadDatabase<JSONDatabase>(new JSONDatabase());
} else if (databaseType === DatabaseType.SQL) {
this.loadDatabase<SQLDatabase>(new SQLDatabase());
} else {
logger.error('Unknown database type.');
}
}
我的JSONDatabase
class:
export class JSONDatabase implements IDatabase {
dbType = DatabaseType.JSON;
constructor(logger: LoggerService, io: IOService) {
logger.log(`Doing something...`)
}
}
但是,问题是如果我想让我的 JSONDatabase
利用注入,即。它需要 IOService
和 LoggerService
,我需要从 DatabaseService
构造函数添加参数,而不是通过 Nest 的 IoC 容器注入它们。
Expected 2 arguments, but got 0 [ts(2554)]
json.database.ts(7, 15): An argument for 'logger' was not provided.
这是执行此操作的正确方法吗?我觉得手动传递这些引用是不正确的,我应该使用 Nest 的自定义提供程序,但是,我不太了解关于这个主题的 Nest 文档。我基本上希望能够 new JSONDatabase()
而不必将引用传递给构造函数并让 Nest.js IoC 容器已经注入现有的单例(运行时依赖注入?)。
我在这里的想法可能完全偏离了基础,但我并没有那么多地使用 Nest,所以我主要是凭直觉工作。感谢您的帮助。
您现在遇到的问题是因为您在调用 new JSONDatabase()
时手动实例化 JSONDatabase,而不是利用 NestJS 提供的 DI。由于构造函数需要 2 个参数(LoggerService 和 IOService)并且您提供 none,它失败并显示消息
Expected 2 arguments, but got 0 [ts(2554)]
我认为根据您的用例,您可以尝试几个不同的选项
- 如果您在启动时获取配置并在应用程序生命周期中设置一次数据库,您可以使用具有
useFactory
语法的自定义提供程序。
const providers = [
{
provide: DatabaseService,
useFactory: (logger: LoggerService, io: IOService, config: YourConfigService): IDatabase => {
if (config.databaseType === DatabaseType.JSON) {
return new JSONDatabase(logger, io);
} else if (databaseType === DatabaseType.SQL) {
return new SQLDatabase(logger, io);
} else {
logger.error('Unknown database type.');
}
},
inject: [LoggerService, IOService, YourConfigService]
},
];
@Module({
providers,
exports: providers
})
export class YourModule {}
如果您有 LoggerService
、IOService
和 YourConfigurationService
注释 @Injectable()
NestJS 会将它们注入到 useFactory 上下文中。您可以在那里检查数据库类型并手动实例化正确的 IDatabase
实现。这种方法的缺点是您无法在运行时轻松更改数据库。 (这可能适合您的用例)
- 您可以使用 strategy/factory 模式根据类型获得正确的实现。假设您有一种方法可以根据特定参数保存到不同的数据库。
@Injectable()
export class SomeService {
constructor(private readonly databaseFactory: DatabaseFactory){}
method(objectToSave: Object, type: DatabaseType) {
databaseFactory.getService(type).save(objectToSave);
}
}
@Injectable()
export class DatabaseFactory {
constructor(private readonly moduleRef: ModuleRef) {}
getService(type: DatabaseType): IDatabase {
this.moduleRef.get(`${type}Database`);
}
}
上面代码的思路是,根据数据库类型,从 NestJS 作用域中获取正确的单例。这样,如果您愿意,可以很容易地添加一个新数据库——只需添加一个新类型及其实现即可。 (并且您的代码可以同时处理多个数据库!)
- 我也相信你可以简单地将已经注入的
LoggerService
和 IOService
传递给你手动创建的 DatabasesService
(你需要添加 IOService
作为依赖共 DatabaseServce
@Injectable()
export class DatabaseService {
constructor(common: CommonService, logger: LoggerService, ioService: IOService) {
// eslint-disable-next-line prettier/prettier
const databaseType: DatabaseType = common.serverConfig.dbType as DatabaseType;
if (databaseType === DatabaseType.JSON) {
this.loadDatabase<JSONDatabase>(new JSONDatabase(logger, ioService));
} else if (databaseType === DatabaseType.SQL) {
this.loadDatabase<SQLDatabase>(new SQLDatabase(logger, ioService));
} else {
logger.error('Unknown database type.');
}
}
}
我想我可能误解了 Nest.js 的 IoC 容器,或者整个 DI。
我有一个 class、JSONDatabase
,我想根据一些配置值(可以是 JSON 或 SQL)实例化自己。
我的 DatabaseService
提供商:
constructor(common: CommonService, logger: LoggerService) {
// eslint-disable-next-line prettier/prettier
const databaseType: DatabaseType = common.serverConfig.dbType as DatabaseType;
if (databaseType === DatabaseType.JSON) {
this.loadDatabase<JSONDatabase>(new JSONDatabase());
} else if (databaseType === DatabaseType.SQL) {
this.loadDatabase<SQLDatabase>(new SQLDatabase());
} else {
logger.error('Unknown database type.');
}
}
我的JSONDatabase
class:
export class JSONDatabase implements IDatabase {
dbType = DatabaseType.JSON;
constructor(logger: LoggerService, io: IOService) {
logger.log(`Doing something...`)
}
}
但是,问题是如果我想让我的 JSONDatabase
利用注入,即。它需要 IOService
和 LoggerService
,我需要从 DatabaseService
构造函数添加参数,而不是通过 Nest 的 IoC 容器注入它们。
Expected 2 arguments, but got 0 [ts(2554)]
json.database.ts(7, 15): An argument for 'logger' was not provided.
这是执行此操作的正确方法吗?我觉得手动传递这些引用是不正确的,我应该使用 Nest 的自定义提供程序,但是,我不太了解关于这个主题的 Nest 文档。我基本上希望能够 new JSONDatabase()
而不必将引用传递给构造函数并让 Nest.js IoC 容器已经注入现有的单例(运行时依赖注入?)。
我在这里的想法可能完全偏离了基础,但我并没有那么多地使用 Nest,所以我主要是凭直觉工作。感谢您的帮助。
您现在遇到的问题是因为您在调用 new JSONDatabase()
时手动实例化 JSONDatabase,而不是利用 NestJS 提供的 DI。由于构造函数需要 2 个参数(LoggerService 和 IOService)并且您提供 none,它失败并显示消息
Expected 2 arguments, but got 0 [ts(2554)]
我认为根据您的用例,您可以尝试几个不同的选项
- 如果您在启动时获取配置并在应用程序生命周期中设置一次数据库,您可以使用具有
useFactory
语法的自定义提供程序。
const providers = [
{
provide: DatabaseService,
useFactory: (logger: LoggerService, io: IOService, config: YourConfigService): IDatabase => {
if (config.databaseType === DatabaseType.JSON) {
return new JSONDatabase(logger, io);
} else if (databaseType === DatabaseType.SQL) {
return new SQLDatabase(logger, io);
} else {
logger.error('Unknown database type.');
}
},
inject: [LoggerService, IOService, YourConfigService]
},
];
@Module({
providers,
exports: providers
})
export class YourModule {}
如果您有 LoggerService
、IOService
和 YourConfigurationService
注释 @Injectable()
NestJS 会将它们注入到 useFactory 上下文中。您可以在那里检查数据库类型并手动实例化正确的 IDatabase
实现。这种方法的缺点是您无法在运行时轻松更改数据库。 (这可能适合您的用例)
- 您可以使用 strategy/factory 模式根据类型获得正确的实现。假设您有一种方法可以根据特定参数保存到不同的数据库。
@Injectable()
export class SomeService {
constructor(private readonly databaseFactory: DatabaseFactory){}
method(objectToSave: Object, type: DatabaseType) {
databaseFactory.getService(type).save(objectToSave);
}
}
@Injectable()
export class DatabaseFactory {
constructor(private readonly moduleRef: ModuleRef) {}
getService(type: DatabaseType): IDatabase {
this.moduleRef.get(`${type}Database`);
}
}
上面代码的思路是,根据数据库类型,从 NestJS 作用域中获取正确的单例。这样,如果您愿意,可以很容易地添加一个新数据库——只需添加一个新类型及其实现即可。 (并且您的代码可以同时处理多个数据库!)
- 我也相信你可以简单地将已经注入的
LoggerService
和IOService
传递给你手动创建的DatabasesService
(你需要添加IOService
作为依赖共DatabaseServce
@Injectable()
export class DatabaseService {
constructor(common: CommonService, logger: LoggerService, ioService: IOService) {
// eslint-disable-next-line prettier/prettier
const databaseType: DatabaseType = common.serverConfig.dbType as DatabaseType;
if (databaseType === DatabaseType.JSON) {
this.loadDatabase<JSONDatabase>(new JSONDatabase(logger, ioService));
} else if (databaseType === DatabaseType.SQL) {
this.loadDatabase<SQLDatabase>(new SQLDatabase(logger, ioService));
} else {
logger.error('Unknown database type.');
}
}
}