在NestJS中可以以多种方式自定义Providers。以下是一些常见的方法:
值提供者用于提供一些硬编码的值,例如配置对象或常量。这类提供者通过 useValue
关键字来指定要注入的值。
使用过程:
provide
属性来指定令牌(通常是一个字符串或符号)。useValue
属性来提供一个硬编码的值。示例:
import { Module } from '@nestjs/common';
@Module({
providers: [
{
provide: 'API_KEY',
useValue: '12345-ABCDE',
},
],
})
export class AppModule {}
类提供者用于将类实例作为依赖注入。这是最常见的提供者类型,通常用于服务类。
使用过程:
providers
数组中使用该类。provide
关键字指定一个令牌,并使用 useClass
来指定类。示例:
import { Module } from '@nestjs/common';
class MyService {
// 服务逻辑
}
@Module({
providers: [
{
provide: 'MyService',
useClass: MyService,
},
],
})
export class AppModule {}
工厂提供者通过工厂函数来创建提供者实例。这种方式适用于需要动态创建依赖项的场景。
使用过程:
providers
数组中使用这个工厂函数。provide
关键字指定一个令牌,并使用 useFactory
来指定工厂函数。示例:
import { Module } from '@nestjs/common';
@Module({
providers: [
{
provide: 'ASYNC_CONNECTION',
useFactory: async () => {
const connection = await createConnection();
return connection;
},
},
],
})
export class AppModule {}
异步提供者是工厂提供者的一个变种,允许在提供者实例化之前执行一些异步操作。
使用过程:
providers
数组中使用这个异步函数。provide
关键字指定一个令牌,并使用 useFactory
来指定异步工厂函数。示例:
import { Module } from '@nestjs/common';
@Module({
providers: [
{
provide: 'ASYNC_CONNECTION',
useFactory: async () => {
const connection = await createConnection();
return connection;
},
},
],
})
export class AppModule {}
别名提供者用于为已存在的提供者创建一个别名。
使用过程:
useExisting
指向现有的服务或提供者。示例:
import { Module } from '@nestjs/common';
class ActualService {
// 实际服务的逻辑
}
@Module({
providers: [
ActualService,
{
provide: 'AliasService',
useExisting: ActualService,
},
],
})
export class AppModule {}
多提供者用于在一个令牌下注册多个提供者,通常用于创建插件系统或聚合相同类型的服务。
使用过程:
providers
数组中定义多个提供者。multi
属性设置为 true
。
示例:
import { Module } from '@nestjs/common';
class MyService {
// 服务逻辑
}
class AnotherService {
// 另一个服务的逻辑
}
@Module({
providers: [
{
provide: 'MY_SERVICE',
useClass: MyService,
multi: true
},
{
provide: 'MY_SERVICE',
useClass: AnotherService,
multi: true
},
],
})
export class AppModule {}
以上是 NestJS 中六种自定义提供者的具体使用过程。这些提供者可以灵活地应用于各种场景,满足不同的开发需求。
在 NestJS 中,inject
选项用于自定义 provider 时,用来指定依赖项的注入。这是在创建复杂 provider 或者在提供 provider 时需要某些依赖项时非常有用的特性。inject
选项通常与 useFactory
或 useClass
结合使用。
useFactory
和 inject
当使用工厂函数 (useFactory
) 定义 provider 时,inject
选项可以指定哪些依赖项需要被注入到这个工厂函数中。这些依赖项可以是其他已注册的 provider、常量值等。
例子:
假设有一个配置服务 (ConfigService
) 和一个日志服务 (LoggerService
),我们需要在工厂函数中使用这些服务来配置另一个服务。
import { Module, Injectable } from '@nestjs/common';
@Injectable()
class ConfigService {
get(key: string): string {
// 假设是从某个配置源获取配置
return 'some_value';
}
}
@Injectable()
class LoggerService {
log(message: string) {
console.log(message);
}
}
// 使用工厂函数创建 provider
@Module({
providers: [
ConfigService,
LoggerService,
{
provide: 'CustomService',
useFactory: (configService: ConfigService, loggerService: LoggerService) => {
const value = configService.get('some_key');
loggerService.log(`配置值:${value}`);
// 根据配置创建并返回实例
return new SomeService(value);
},
inject: [ConfigService, LoggerService], // 指定要注入的服务
},
],
})
export class AppModule {}
useClass
和 inject
虽然 useClass
通常不需要 inject
选项,因为 NestJS 可以自动处理类的依赖注入,但在某些高级场景下,你可能需要显式地指定依赖项。这通常用于动态模块或更复杂的依赖注入场景。
例子:
假设有一个复杂的场景,其中一个类依赖于动态决定的服务。
import { Module, DynamicModule } from '@nestjs/common';
class ComplexService {
constructor(private dynamicService: any) {}
// ...
}
@Module({})
export class ComplexModule {
static register(dynamicProvider): DynamicModule {
return {
module: ComplexModule,
providers: [
{
provide: ComplexService,
useClass: ComplexService,
inject: [dynamicProvider.provide], // 显式指定依赖项
},
dynamicProvider,
],
exports: [ComplexService],
};
}
}
在这个例子中,ComplexService
的实例化依赖于动态提供的服务。通过使用 useClass
和 inject
,我们能够在模块动态注册时灵活指定依赖项。
这两种方式展示了如何使用 inject
选项来注入依赖项,从而在 NestJS 中创建更灵活和动态的 provider。