NestJS提供者(Provider) #

什么是提供者? #

提供者是NestJS中的一个核心概念。提供者是一个被@Injectable()装饰器装饰的类,它可以被注入到其他类中(如控制器、其他服务等)。提供者通常是服务(Service),但也可以是仓库、工厂、助手等。

基本服务 #

创建服务 #

使用CLI创建服务:

bash
nest g service users

生成的代码:

typescript
import { Injectable } from '@nestjs/common';

@Injectable()
export class UsersService {}

完整的服务示例 #

typescript
import { Injectable } from '@nestjs/common';
import { User } from './interfaces/user.interface';

@Injectable()
export class UsersService {
  private readonly users: User[] = [];

  create(user: User) {
    this.users.push(user);
  }

  findAll(): User[] {
    return this.users;
  }

  findOne(id: number): User {
    return this.users.find(user => user.id === id);
  }

  update(id: number, user: User) {
    const index = this.users.findIndex(u => u.id === id);
    if (index !== -1) {
      this.users[index] = { ...this.users[index], ...user };
    }
    return this.users[index];
  }

  remove(id: number) {
    const index = this.users.findIndex(u => u.id === id);
    if (index !== -1) {
      this.users.splice(index, 1);
    }
  }
}

注册提供者 #

提供者需要在模块中注册:

typescript
import { Module } from '@nestjs/common';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';

@Module({
  controllers: [UsersController],
  providers: [UsersService],
})
export class UsersModule {}

依赖注入 #

构造函数注入 #

typescript
import { Controller } from '@nestjs/common';
import { UsersService } from './users.service';

@Controller('users')
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Get()
  findAll() {
    return this.usersService.findAll();
  }
}

服务间依赖 #

typescript
@Injectable()
export class UsersService {
  constructor(
    private readonly databaseService: DatabaseService,
    private readonly loggerService: LoggerService,
  ) {}
}

提供者注册方式 #

类提供者 #

最常用的方式:

typescript
providers: [UsersService]

// 等价于
providers: [
  {
    provide: UsersService,
    useClass: UsersService,
  },
]

值提供者 #

使用现有值:

typescript
import { User } from './user.mock';

providers: [
  {
    provide: 'MOCK_USER',
    useValue: new User(),
  },
]

工厂提供者 #

使用工厂函数动态创建:

typescript
providers: [
  {
    provide: 'DATABASE_CONNECTION',
    useFactory: (configService: ConfigService) => {
      return createConnection({
        host: configService.get('DB_HOST'),
        port: configService.get('DB_PORT'),
      });
    },
    inject: [ConfigService],
  },
]

别名提供者 #

为现有提供者创建别名:

typescript
providers: [
  UsersService,
  {
    provide: 'UserServiceAlias',
    useExisting: UsersService,
  },
]

自定义提供者Token #

使用字符串Token #

typescript
providers: [
  {
    provide: 'CONFIG_OPTIONS',
    useValue: { apiKey: 'xxx', timeout: 5000 },
  },
]

// 注入时使用@Inject
constructor(
  @Inject('CONFIG_OPTIONS') private options: ConfigOptions,
) {}

使用Symbol Token #

typescript
export const CONFIG_OPTIONS = Symbol('CONFIG_OPTIONS');

providers: [
  {
    provide: CONFIG_OPTIONS,
    useValue: { apiKey: 'xxx' },
  },
]

// 注入
constructor(
  @Inject(CONFIG_OPTIONS) private options: ConfigOptions,
) {}

使用InjectionToken(TypeScript) #

typescript
import { InjectionToken } from '@nestjs/core';

export const CONFIG_OPTIONS = new InjectionToken<ConfigOptions>('CONFIG_OPTIONS');

异步提供者 #

返回Promise的工厂函数:

typescript
providers: [
  {
    provide: 'ASYNC_CONNECTION',
    useFactory: async () => {
      const connection = await createConnection();
      return connection;
    },
  },
]

提供者示例 #

数据库连接提供者 #

typescript
import { Injectable, OnModuleDestroy } from '@nestjs/common';
import { createConnection, Connection } from 'mysql2/promise';

@Injectable()
export class DatabaseService implements OnModuleDestroy {
  private connection: Connection;

  async onModuleInit() {
    this.connection = await createConnection({
      host: 'localhost',
      user: 'root',
      database: 'test',
    });
  }

  async onModuleDestroy() {
    await this.connection.end();
  }

  async query(sql: string, params?: any[]) {
    const [rows] = await this.connection.execute(sql, params);
    return rows;
  }
}

缓存服务 #

typescript
import { Injectable } from '@nestjs/common';

@Injectable()
export class CacheService {
  private cache = new Map<string, { value: any; expire: number }>();

  set(key: string, value: any, ttl: number = 60000) {
    this.cache.set(key, {
      value,
      expire: Date.now() + ttl,
    });
  }

  get<T>(key: string): T | null {
    const item = this.cache.get(key);
    if (!item) return null;

    if (Date.now() > item.expire) {
      this.cache.delete(key);
      return null;
    }

    return item.value as T;
  }

  delete(key: string) {
    this.cache.delete(key);
  }

  clear() {
    this.cache.clear();
  }
}

日志服务 #

typescript
import { Injectable, LoggerService, Scope } from '@nestjs/common';

@Injectable({ scope: Scope.TRANSIENT })
export class CustomLoggerService implements LoggerService {
  private context?: string;

  setContext(context: string) {
    this.context = context;
  }

  log(message: string) {
    console.log(`[${this.context}] ${message}`);
  }

  error(message: string, trace?: string) {
    console.error(`[${this.context}] ERROR: ${message}`);
    if (trace) console.error(trace);
  }

  warn(message: string) {
    console.warn(`[${this.context}] WARN: ${message}`);
  }

  debug(message: string) {
    console.debug(`[${this.context}] DEBUG: ${message}`);
  }

  verbose(message: string) {
    console.log(`[${this.context}] VERBOSE: ${message}`);
  }
}

配置服务 #

typescript
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';

@Injectable()
export class AppConfigService {
  constructor(private configService: ConfigService) {}

  get databaseHost(): string {
    return this.configService.get<string>('DATABASE_HOST');
  }

  get databasePort(): number {
    return this.configService.get<number>('DATABASE_PORT', 3306);
  }

  get jwtSecret(): string {
    return this.configService.get<string>('JWT_SECRET');
  }

  get isDevelopment(): boolean {
    return this.configService.get<string>('NODE_ENV') === 'development';
  }

  get isProduction(): boolean {
    return this.configService.get<string>('NODE_ENV') === 'production';
  }
}

仓库模式 #

typescript
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './entities/user.entity';

@Injectable()
export class UsersRepository {
  constructor(
    @InjectRepository(User)
    private readonly repository: Repository<User>,
  ) {}

  async findAll(): Promise<User[]> {
    return this.repository.find();
  }

  async findOne(id: number): Promise<User | null> {
    return this.repository.findOne({ where: { id } });
  }

  async create(userData: Partial<User>): Promise<User> {
    const user = this.repository.create(userData);
    return this.repository.save(user);
  }

  async update(id: number, userData: Partial<User>): Promise<User | null> {
    await this.repository.update(id, userData);
    return this.findOne(id);
  }

  async delete(id: number): Promise<void> {
    await this.repository.delete(id);
  }
}

提供者作用域 #

typescript
import { Injectable, Scope } from '@nestjs/common';

@Injectable({ scope: Scope.REQUEST })
export class RequestScopedService {
  private requestId: string;

  setRequestId(id: string) {
    this.requestId = id;
  }

  getRequestId(): string {
    return this.requestId;
  }
}
作用域 说明 性能影响
DEFAULT 单例,应用生命周期内唯一
REQUEST 每个请求创建新实例 中等
TRANSIENT 每次注入创建新实例 较高

可选提供者 #

typescript
import { Injectable, Optional } from '@nestjs/common';

@Injectable()
export class HttpService {
  constructor(
    @Optional()
    private readonly logger?: LoggerService,
  ) {}

  request(url: string) {
    this.logger?.log(`Requesting ${url}`);
  }
}

总结 #

本章深入学习了NestJS提供者:

  • 服务的创建和使用
  • 提供者的注册方式
  • 自定义提供者Token
  • 工厂提供者和异步提供者
  • 仓库模式的实现

接下来,让我们学习 依赖注入

最后更新:2026-03-28