NestJS系列(3)- Provider(提供者)

👋 上一集我们把控制器 比作了餐厅的服务员 ,专门负责接客、点菜、上菜。但你想过没有,服务员手里的菜是谁做的?当然是后厨的厨师们啦!

在 NestJS 的世界里, Provider(提供者) 就是这群神通广大的"后厨天团"。今天,我们就用最轻松的方式,把这个核心概念彻底拿捏!


1. 🤔 Provider 到底是什么玩意儿?

想象一下我们的餐厅:

  • 服务员(控制器):笑容满面地记录客人要的"宫保鸡丁"。
  • 然后呢? 服务员自己并不会炒菜,他需要把订单递给后厨
  • 后厨(Provider):一群大师傅,有的切菜,有的炒菜,有的摆盘。他们收到订单,一通操作,变出一盘香喷喷的菜,交给服务员端出去。

在代码世界里:

  • Provider 就是负责干活 的类。比如:从数据库取数据、调用外部API、做一些复杂的计算、发送邮件......所有业务逻辑都在这里。
  • 最常见的 Provider 就是 Service(服务),但你也可以有 Repository(仓库)、Factory(工厂)、Helper(助手)等等,它们统统可以被打上 Provider 的标签。

核心思想就一句话: Provider 就是那些"真正干活"的家伙,而且他们可以互相帮忙、互相依赖。


2. 🏷️ 怎么识别一个 Provider?看它脑门上的标签:@Injectable()

在 Nest 里,如果一个类想成为 Provider,它必须在脑门上贴一个特殊的便利贴:@Injectable()

typescript 复制代码
// cats.service.ts
import { Injectable } from '@nestjs/common';

@Injectable()  // ← 就是这个!贴了这个标签,Nest就知道:哦,这是个可以管理的Provider
export class CatsService {
  private cats = ['加菲猫', '汤姆猫'];

  findAll() {
    return this.cats;
  }

  create(cat: string) {
    this.cats.push(cat);
  }
}

@Injectable() 这个装饰器告诉 Nest:"嘿,注意这个类!它可以被注入到别的类里,也可以在里面注入别的Provider。" 就像厨师身上挂着"在职员工"的工牌,系统知道他是自己人。


3. 🤝 服务员(控制器)怎么找后厨(Provider)帮忙?

关键来了!服务员手里没有菜,他得找厨师要。怎么找?靠 依赖注入(Dependency Injection)------一个听起来很拽,其实很简单的概念。

看这段代码:

typescript 复制代码
// cats.controller.ts
import { Controller, Get, Post, Body } from '@nestjs/common';
import { CatsService } from './cats.service';  // 1. 先把厨师请进来

@Controller('cats')
export class CatsController {
  // 2. 在构造函数里"要人"!private readonly 是一步到位的小技巧
  constructor(private readonly catsService: CatsService) {}

  @Get()
  findAll() {
    // 3. 直接让厨师干活!
    return this.catsService.findAll();
  }

  @Post()
  create(@Body('name') name: string) {
    this.catsService.create(name);
    return '猫咪添加成功';
  }
}

依赖注入的精髓就是: 你不需要自己 new CatsService(),只需要在构造函数里说"我要一个 CatsService",Nest 就会自动给你准备好一个现成的,直接拿来用!

这就好比服务员根本不需要自己去后厨"创建"一个厨师(新招人),他只需要对着对讲机喊一声"来份宫保鸡丁",自然会有厨师做好了递出来。谁做的?不用管,反正有就行。


4. 📝 注册登记:让餐厅经理知道你有这个厨师

等等,还没完!你虽然写了 CatsService 这个厨师,也在控制器里说要找他帮忙,但**餐厅经理(Nest 的 IoC 容器)**还不知道有这号人物呢!你得把厨师的名字登记在员工手册上。

这个"员工手册"就是 模块(Module)providers 数组:

typescript 复制代码
// app.module.ts
import { Module } from '@nestjs/common';
import { CatsController } from './cats/cats.controller';
import { CatsService } from './cats/cats.service';  // 1. 引入厨师

@Module({
  controllers: [CatsController],   // 服务员名单
  providers: [CatsService],         // 2. 厨师名单 ← 在这里登记!
})
export class AppModule {}

登记完之后,Nest 就全明白了:

  • CatsController 依赖于 CatsService
  • CatsService 已经注册为 Provider
  • ✅ 当 CatsController 被创建时,Nest 会自动创建(或复用)一个 CatsService 实例,并注入进去

5. 🔄 依赖注入的"隐藏福利":单例模式

这里有个超赞的特性:默认情况下,Nest 里的 Provider 都是**单例(Singleton)**的。

啥意思?就是同一个 Provider 在整个应用里只会被创建一次,然后到处复用。

  • 如果你在三个不同的控制器里都注入了 CatsService,它们拿到的是同一个实例
  • 好处是:节省内存,数据共享方便(比如在多个控制器间共享同一个缓存)。

这就像餐厅里只有一个"凉菜大师傅",所有服务员下单"拍黄瓜",都是找他做,他不会分身,但效率极高。


6. 🎁 Provider 的几种"特殊形态"

除了普通的 Service 类,Provider 还有其他几种有趣的玩法,我们快速扫一眼,有个印象就行:

A. 😎 可选依赖:不是必须有的厨师

有时候,某些依赖不是必须的,有就用,没有也能凑合。比如你的服务可能依赖一个配置对象,但如果没有,就用默认配置。

这时可以用 @Optional() 装饰器:

typescript 复制代码
@Injectable()
export class HttpService {
  constructor(
    @Optional()  // 告诉 Nest:这个依赖可有可无
    @Inject('HTTP_OPTIONS') private httpClient: any
  ) {}
}

B. 🏷️ 属性注入:懒人专属

我们之前都是在构造函数里注入(构造函数注入)。但如果你不想写构造函数,也可以直接在属性上用 @Inject()

typescript 复制代码
@Injectable()
export class HttpService {
  @Inject('HTTP_OPTIONS')  // 直接在属性上注入
  private httpClient: any;
}

不过官方建议:能用构造函数注入,就用构造函数注入,因为代码更清晰,一眼就能看出这个类依赖什么。

C. 🧙‍♂️ 自定义 Provider:高级玩法

有些时候,你不想直接提供一个类,而是想提供一个值、一个工厂函数(动态创建)、或者一个异步的 Provider。这属于高级内容,等你把基础打牢了再去探索。


7. 🗺️ 回顾一下:我们现在有了什么?

经过两篇文章,我们的餐厅已经初具规模:

角色 对应概念 职责
👩‍💼 服务员 Controller 接收请求、返回响应
👨‍🍳 厨师 Provider(Service) 处理业务逻辑、操作数据
🏢 餐厅经理 IoC 容器 管理服务员和厨师,自动满足依赖
📋 员工手册 Module 登记服务员和厨师名单

工作流程:

  1. 客户端(客人)发出请求(点菜)
  2. 控制器(服务员)接收请求(记录菜单)
  3. 控制器调用 Provider(把菜单递给后厨)
  4. Provider 处理业务(厨师做菜)
  5. 控制器返回响应(服务员上菜)

8. 🎯 总结:Provider 是什么?

  • 定义 :用 @Injectable() 装饰的类,负责处理具体的业务逻辑。
  • 作用:让控制器保持"苗条",只负责调度,不负责干活。
  • 核心机制:依赖注入------你只需要声明"我需要什么",Nest 自动给你准备好。
  • 注册 :必须在模块的 providers 数组里登记。
  • 特性:默认是单例,整个应用共享一个实例。

下一步,我们会介绍模块(Module)------也就是那个"员工手册",看看怎么把服务员和厨师组织成一个个独立的部门。

相关推荐
helloweilei9 小时前
NestJS系列(2)- 控制器(Controller)
nestjs·全栈
helloweilei11 小时前
NestJS系列(1)- nestjs简介及项目初始化
nestjs·全栈
刘晓飞1 天前
nestjs的类为控制器(Controller)
nestjs
前端双越老师1 天前
RAG 完全指南:从概念到生产实践
人工智能·agent·全栈
onebyte8bits1 天前
NestJS 系列教程(十五):缓存体系设计 —— Redis、接口缓存与缓存三大问题解决方案
数据库·redis·后端·缓存·nestjs
小成C2 天前
Vibe Coding 时代,研发体系该怎么重新分工
人工智能·架构·全栈
小蜜蜂dry2 天前
nestjs学习 - 中间件(Middleware)
前端·nestjs
非优秀程序员3 天前
OpenClaw 教学:25 个工具 + 53 个技能完整指南
人工智能·开源·全栈
今日无bug3 天前
Git 提交:用全栈技术打造智能 Commit Message 生成器
git·全栈