定义

Provider 只是一个用 @Injectable() 装饰器注释的类,用于在 NestJS 中实现依赖注入
当 NestJS 启动时,会扫描所有 Provider,并将其注册到 IoC 容器中
当其他组件需要该 Provider 时,组件通过类型从 IoC 容器中获取该 Provider,IoC 容器会自动解析依赖、创建实例、并将其注入到该组件中

基本用法

app.service.ts 定义一个 Provider

import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
  getHello(): string {
    return 'Hello World!';
  }
}

app.module.ts 定义一个 Module,将 AppService Provider 注册到 IoC 容器中,同时将 AppController 注册到 Module 中

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

app.controller.ts 定义一个 Controller,将 AppService Provider 注入到该 Controller 中

import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
    // 构造函数注入 AppService Provider
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
}

自定义 名称

在app.module.ts中,可以自定义 Provider 的名称,原来的基本用法就是语法糖,实际传入的参数是一个对象

@Module({
  controllers: [AppController],
  providers: [{
    provide: 'APP_SERVICE',
    useClass: AppService,
  }],
})
export class AppModule {}

使用了自定义名称的 Provider,需要在构造函数中使用 @Inject 装饰器注入该 Provider ,并指定自定义名称

@Controller()
export class AppController {
    // 构造函数注入 AppService Provider
  constructor(@Inject('APP_SERVICE') private readonly appService: AppService) {}

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
}

自定义 注入值

通过useValue属性 可以在 Provider 中定义自定义的注入值,用于在构造函数中注入非 Provider 类型的值

@Module({
  controllers: [AppController],
  providers: [{
    provide: 'str',
    useValue: 'Hello World!',
  }],
})
export class AppModule {}

可以在构造函数中使用 @Inject 装饰器注入自定义的注入值

@Controller()
export class AppController {
    // 构造函数注入 str Provider
  constructor(@Inject('str') private readonly str: string) {}
}

工厂模式

工厂模式是一种设计模式,用于创建对象的实例
在 NestJS 中,可以通过工厂模式 来动态创建 Provider 的实例/服务

app.service.ts 定义一个 Provider,用于判断是否成功

@Injectable()
export class AppService {
  isOk(): boolean {
    return true;
  }
}

app.module.ts 定义一个 Module

@Module({
  controllers: [AppController],
  providers: [{
      provide: 'FactoryMod',
      inject: [AppService], // 注入 AppService Provider, 做工厂模式的依赖
      useFactory: (appService: AppService) => {
        // 根据其他的 业务逻辑 来动态创建实例/服务
        if (appService.isOk()) {
          return 'FactoryMod Ok';
        } else {
          return 'FactoryMod Failed';
        }
      },
    },],
})
export class AppModule {}

app.controller.ts 定义一个 Controller,将 FactoryMod Provider 注入到该 Controller 中

@Controller()
export class AppController {
    // 构造函数注入 FactoryMod Provider
  constructor(@Inject('FactoryMod') private readonly factoryMod: string) {}
}
使用 JwtModule 工厂模式

在开启了 monorepo模式的nest项目中使用Jwt认证公共配置

文件:./libs/shared/src/shared.module.ts

import { Global, Module } from '@nestjs/common';
import { SharedService } from './shared.service';
import { PrismaModule } from './prisma/prisma.module';
import { ResponseModule } from './response/response.module';

import { ConfigModule, ConfigService } from '@nestjs/config';
import { JwtModule } from '@nestjs/jwt';
@Global()
@Module({
  providers: [SharedService],
  exports: [SharedService, PrismaModule, ResponseModule, JwtModule],
  imports: [
    // ORM 模块,用于数据库数据库操作
    PrismaModule,
    // 统一响应模块,用于处理响应
    ResponseModule,
    // 配置模块,用于加载环境变量
    ConfigModule.forRoot({
      envFilePath: '.env',
      isGlobal: true,
    }),
    // 异步 JWT 模块,用于认证
    JwtModule.registerAsync({
      /** 引入配置模块 */
      imports: [ConfigModule],
      /** 注入配置服务 */
      inject: [ConfigService],
      /** 配置工厂函数 */
      useFactory: (configService: ConfigService) => {
        // 根据配置动态创建 JWT 模块的实例
        return {
          global: true, // 全局模块
          secret: configService.get('SECRET_KEY'), // 密钥
          signOptions: { expiresIn: '1h' }, // 过期时间为1小时
        };
      },
    }),
  ],
})
export class SharedModule {}

在某个微服务的 auth 模块中,引入 SharedModule,即可使用 JwtModule 工厂模式

import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { SharedModule } from '@libs/shared';
@Module({
  /** 引入共享模块: 包含 JwtModule 配置*/
  imports: [SharedModule],
  /** 引入服务 */
  providers: [AuthService],
  /** 导出服务 */
  exports: [AuthService],
})
export class AuthModule {}

声明一个 Provider AuthService,专门用于生成和验证 JWT 令牌

import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';

@Injectable()
export class AuthService {
  constructor(private jwtService: JwtService) {}

  generateToken(payload: TokenPayload): Token {
    return {
      accessToken: this.jwtService.sign<TypedTokenPayload>({
        ...payload,
        tokenType: 'access',
      }),
      refreshToken: this.jwtService.sign<TypedTokenPayload>(
        {
          ...payload,
          tokenType: 'refresh',
        },
        {
          expiresIn: '7d',
        },
      ),
    };
  }

  verifyToken(token: string): TypedTokenPayload | null {
    try {
        // 这个JwtService.verify 方法会直接抛出错误,需要手动捕获异常
      return this.jwtService.verify<TypedTokenPayload>(token);
    } catch (error) {
      return null;
    }
  }
}

异步模式

useFactory 方法可以异步创建 Provider 的实例/服务
但即使返回了 Promise,Nest 解析 Promise 后,会将 Promise 解析后的结果作为 Provider 的实例/服务,而不是直接返回 Promise

    {
      provide: 'FactoryMod',
      inject: [AppService], // 使用类作为令牌,与注册方式一致
      useFactory: (appService: AppService) => {
        if (appService.isOk()) {
          return new Promise((resolve) =>
            setTimeout(() => resolve('FactoryMod Ok'), 1000),
          );
        } else {
          return new Promise((resolve) =>
            setTimeout(() => resolve('FactoryMod Failed'), 1000),
          );
        }
      },
    },

总结

  • Provider 是 NestJS 依赖注入的基础,用 @Injectable() 标记

  • 支持自定义名称、自定义值、工厂模式、异步创建等多种用法

  • 配合 @Inject() 可以灵活注入各种依赖

  • 工厂模式特别适合需要根据配置动态创建实例的场景(如 JWT 配置)