提供者(Provider)的概念
提供者是 NestJS 中的一个核心概念,它是一个用 @Injectable() 装饰器装饰的类,可以被注入到其他类中。提供者可以处理业务逻辑、数据访问、与其他服务的集成等。
提供者的类型
- 服务(Services):封装业务逻辑
- 仓库(Repositories):处理数据访问
- 工厂(Factories):创建和配置对象
- 提供者(Providers):任何可以被注入的类
服务(Service)
服务是最常见的提供者类型,用于封装业务逻辑和可重用的功能。
基本服务结构
typescriptimport { Injectable } from '@nestjs/common'; @Injectable() export class UsersService { private readonly users: any[] = []; create(user: any) { this.users.push(user); return user; } findAll() { return this.users; } findOne(id: number) { return this.users.find(user => user.id === id); } update(id: number, updateUserDto: any) { const user = this.findOne(id); if (user) { Object.assign(user, updateUserDto); return user; } return null; } remove(id: number) { const index = this.users.findIndex(user => user.id === id); if (index > -1) { this.users.splice(index, 1); return true; } return false; } }
在控制器中使用服务
typescriptimport { Controller, Get, Post, Body, Param, Put, Delete } from '@nestjs/common'; import { UsersService } from './users.service'; @Controller('users') export class UsersController { constructor(private readonly usersService: UsersService) {} @Post() create(@Body() createUserDto: any) { return this.usersService.create(createUserDto); } @Get() findAll() { return this.usersService.findAll(); } }
在模块中注册提供者
方式一:直接提供类
typescriptimport { Module } from '@nestjs/common'; import { UsersController } from './users.controller'; import { UsersService } from './users.service'; @Module({ controllers: [UsersController], providers: [UsersService], }) export class UsersModule {}
方式二:使用 provide 和 useClass
typescript@Module({ providers: [ { provide: UsersService, useClass: UsersService, }, ], }) export class UsersModule {}
方式三:使用 provide 和 useValue
typescript@Module({ providers: [ { provide: 'API_KEY', useValue: 'your-api-key-here', }, ], }) export class AppModule {}
方式四:使用 provide 和 useFactory
typescript@Module({ providers: [ { provide: UsersService, useFactory: (userRepository: UserRepository) => { return new UsersService(userRepository); }, inject: [UserRepository], }, ], }) export class UsersModule {}
方式五:使用 provide 和 useExisting
typescript@Module({ providers: [ UsersService, { provide: 'USERS_SERVICE', useExisting: UsersService, }, ], }) export class UsersModule {}
依赖注入令牌
类作为令牌
typescriptconstructor(private readonly usersService: UsersService) {}
字符串作为令牌
typescriptconstructor(@Inject('API_KEY') private readonly apiKey: string) {}
Symbol 作为令牌
typescriptexport const API_KEY = Symbol('API_KEY'); constructor(@Inject(API_KEY) private readonly apiKey: string) {}
作用域配置
默认作用域(单例)
typescript@Injectable() export class UsersService {}
请求作用域
typescriptimport { Scope } from '@nestjs/common'; @Injectable({ scope: Scope.REQUEST }) export class UsersService {}
瞬时作用域
typescript@Injectable({ scope: Scope.TRANSIENT }) export class UsersService {}
自定义提供者
异步提供者
typescript@Module({ providers: [ { provide: 'ASYNC_CONNECTION', useFactory: async () => { const connection = await createConnection(); return connection; }, }, ], }) export class AppModule {}
动态模块
typescriptimport { DynamicModule, Module } from '@nestjs/common'; @Module({}) export class DatabaseModule { static register(options: DatabaseOptions): DynamicModule { return { module: DatabaseModule, providers: [ { provide: 'DATABASE_OPTIONS', useValue: options, }, DatabaseService, ], exports: [DatabaseService], }; } }
最佳实践
- 单一职责原则:每个服务只负责一个功能领域
- 依赖注入:使用构造函数注入依赖
- 接口隔离:定义清晰的接口契约
- 避免循环依赖:设计时避免服务间的循环依赖
- 使用 DTO:使用数据传输对象来传递数据
- 错误处理:在服务层处理业务逻辑错误
- 可测试性:编写可测试的服务代码
- 文档化:为服务添加清晰的文档注释
服务层设计模式
1. 仓储模式(Repository Pattern)
typescript@Injectable() export class UserRepository { constructor(private readonly dataSource: DataSource) {} async findById(id: number) { return this.dataSource.getRepository(User).findOne({ where: { id } }); } async findAll() { return this.dataSource.getRepository(User).find(); } }
2. 服务模式(Service Pattern)
typescript@Injectable() export class UsersService { constructor( private readonly userRepository: UserRepository, private readonly emailService: EmailService, ) {} async createUser(createUserDto: CreateUserDto) { const user = await this.userRepository.create(createUserDto); await this.emailService.sendWelcomeEmail(user.email); return user; } }
3. 工厂模式(Factory Pattern)
typescript@Injectable() export class UserFactory { createUser(data: any): User { return new User(data); } }
总结
NestJS 提供者和服务系统提供了:
- 灵活的依赖注入机制
- 多种提供者注册方式
- 清晰的代码组织结构
- 高度的可测试性
- 良好的可维护性
掌握提供者和服务是构建 NestJS 应用程序的核心,它们使开发者能够编写松耦合、可重用和可测试的代码。通过合理使用提供者和服务,可以构建出结构清晰、易于维护的企业级应用。