NestJS 是一个基于 Node.js 的渐进式框架,而“提供者(Provider)”是 NestJS 的核心概念之一。理解它就能真正掌握依赖注入(Dependency Injection,简称 DI)在 NestJS 中的使用方式。为了帮助你更好地理解提供者,我将用多个角度和方式来解释:
🧠 什么是 Provider?
在 NestJS 中,Provider(提供者)就是一个可以被 NestJS 注入使用的类或值,它通常用来封装业务逻辑、数据库操作、HTTP 调用等功能。
提供者本质上是一个“可被注入的依赖”。
🧱 构成提供者的三要素
- Token(令牌):用来标识和查找这个 Provider,通常是类名,也可以是字符串或 symbol。
- Provider 本体:一个类、值、工厂函数等。
- Scope(作用域):默认是单例,也可以是请求级或瞬时级。
🧩 举个例子:常见的 Service 提供者
// cats.service.ts
import { Injectable } from '@nestjs/common';
@Injectable()
export class CatsService {
findAll() {
return ['Cat1', 'Cat2'];
}
}
这个 CatsService 被 @Injectable() 装饰器标记之后,就成了一个 Provider,可以被注入到其他类中。
// cats.controller.ts
import { Controller, Get } from '@nestjs/common';
import { CatsService } from './cats.service';
@Controller('cats')
export class CatsController {
constructor(private readonly catsService: CatsService) {}
@Get()
findAll() {
return this.catsService.findAll();
}
}
🔁 Nest 是怎么处理 Provider 的?
NestJS 会做以下几步:
- 看到
@Injectable()标记,就注册为 Provider。 - 把它加进 DI 容器中。
- 如果别的类需要它,就通过构造函数注入。
💡 手动写 Provider 的方式
NestJS 中你可以使用不同方式注册 Provider:
1. 类作为 Provider
{
provide: CatsService, // token
useClass: CatsService,
}
2. 值作为 Provider(useValue)
{
provide: 'CONFIG',
useValue: { apiKey: '123', timeout: 5000 },
}
3. 工厂函数作为 Provider(useFactory)
{
provide: 'ASYNC_CONFIG',
useFactory: async () => {
const data = await fetch('...');
return data;
}
}
🎭 常见疑惑解答
❓为什么叫 Provider,不直接叫 Service 呢?
因为不仅仅是 Service,任何可注入的东西都可以是 Provider:比如 Repository、Config、Logger、甚至是你自己写的函数。
❓Controller 是 Provider 吗?
不是。Controller 是特殊的类,由 Nest 管理,不注入进其他类。
🎓 类比法帮助你理解
可以把 NestJS 的 Provider 系统类比成:
“一个智能的快递仓库”:
- 你告诉它:“我需要一个 CatsService”。
- 它就从仓库中找到、创建并送给你。
- 每个依赖只创建一次(单例),除非你特别要求(scope 改成 request 或 transient)。
🧪 测试中的 Provider
在单元测试中,你也需要自己声明 Provider:
const module = await Test.createTestingModule({
providers: [CatsService],
}).compile();
🧵 总结一句话:
“Provider 是一个用来提供功能或服务的对象,它是 NestJS 构建模块化、解耦系统的核心组成部分。”