# Providers
Providers 是 `Nest` 的一個基本概念。許多基本的 `Nest` 類可能被視為 provider - `service`,` repository`, `factory`, `helper` 等等。 他們都可以通過 `constructor` **注入**依賴關系。 提供者的主要思想是它可以作為依賴**注入**,這意味著對象可以彼此創建各種關系,并且“連接”對象實例的功能在很大程度上可以委托給 `Nest`運行時系統。 Provider 只是一個用 `@Injectable()` 裝飾器注釋的類。

在前面的章節中,我們已經創建了一個簡單的控制器 `CatsController` 。控制器應處理 `HTTP` 請求并將更復雜的任務委托給 **providers**。`Providers` 是純粹的 `JavaScript` 類,在其類聲明之前帶有 `@Injectable()`裝飾器。
> 由于 `Nest` 可以以更多的面向對象方式設計和組織依賴性,因此我們強烈建議遵循 [SOLID](https://en.wikipedia.org/wiki/SOLID) 原則。
## 服務
讓我們從創建一個簡單的 `CatsService` 開始。該服務將負責數據存儲和檢索,其由 `CatsController` 使用,因此把它定義為 `provider`,是一個很好的選擇。因此,我們用 `@Injectable()` 來裝飾這個類 。
> cats.service.ts
```typescript
import { Injectable } from '@nestjs/common';
import { Cat } from './interfaces/cat.interface';
@Injectable()
export class CatsService {
private readonly cats: Cat[] = [];
create(cat: Cat) {
this.cats.push(cat);
}
findAll(): Cat[] {
return this.cats;
}
}
```
> 要使用 `CLI` 創建服務類,只需執行 `$ nest g service cats` 命令。
我們的 `CatsService` 是具有一個屬性和兩個方法的基本類。唯一的新特點是它使用 `@Injectable()` 裝飾器。該 `@Injectable()` 附加有元數據,因此 `Nest` 知道這個類是一個 `Nest` provider。需要注意的是,上面有一個 `Cat` 接口。看起來像這樣:
> interfaces/cat.interface.ts
```typescript
export interface Cat {
name: string;
age: number;
breed: string;
}
```
現在我們有一個服務類來檢索 `cat` ,讓我們在 `CatsController` 里使用它 :
> cats.controller.ts
```typescript
import { Controller, Get, Post, Body } from '@nestjs/common';
import { CreateCatDto } from './dto/create-cat.dto';
import { CatsService } from './cats.service';
import { Cat } from './interfaces/cat.interface';
@Controller('cats')
export class CatsController {
constructor(private catsService: CatsService) {}
@Post()
async create(@Body() createCatDto: CreateCatDto) {
this.catsService.create(createCatDto);
}
@Get()
async findAll(): Promise<Cat[]> {
return this.catsService.findAll();
}
}
```
`CatsService` 是通過類構造函數注入的。注意這里使用了私有的只讀語法。這意味著我們已經在同一位置創建并初始化了 `catsService ` 成員。
## 依賴注入
Nest 是建立在強大的設計模式,通常稱為依賴注入。我們建議在官方的 [Angular文檔](https://angular.cn/guide/dependency-injection)中閱讀有關此概念的精彩文章。
在 `Nest` 中,借助 **TypeScript** 功能,管理依賴項非常容易,因為它們僅按類型進行解析。在下面的示例中,`Nest` 將 `catsService` 通過創建并返回一個實例來解析 `CatsService`(或者,在單例的正常情況下,如果現有實例已在其他地方請求,則返回現有實例)。解析此依賴關系并將其傳遞給控制器的構造函數(或分配給指定的屬性):
```typescript
constructor(private readonly catsService: CatsService) {}
```
## 作用域
Provider 通常具有與應用程序生命周期同步的生命周期(“作用域”)。在啟動應用程序時,必須解析每個依賴項,因此必須實例化每個提供程序。同樣,當應用程序關閉時,每個 provider 都將被銷毀。但是,有一些方法可以改變 provider 生命周期的請求范圍。您可以[在此處](/8/fundamentals?id=注射范圍)詳細了解這些技術。
## 自定義提供者
`Nest` 有一個內置的控制反轉(`"IoC"`)容器,可以解決 providers 之間的關系。 此功能是上述依賴注入功能的基礎,但要比上面描述的要強大得多。`@Injectable()` 裝飾器只是冰山一角, 并不是定義 providers 的唯一方法。相反,您可以使用普通值、類、異步或同步工廠。看看[這里](https://docs.nestjs.com/fundamentals/injection-scopes)找到更多的例子。
## 可選提供者
有時,您可能需要解決一些依賴項。例如,您的類可能依賴于一個**配置對象**,但如果沒有傳遞,則應使用默認值。在這種情況下,關聯變為可選的, `provider` 不會因為缺少配置導致錯誤。
要指示 provider 是可選的,請在 `constructor` 的參數中使用 `@Optional()` 裝飾器。
```typescript
import { Injectable, Optional, Inject } from '@nestjs/common';
@Injectable()
export class HttpService<T> {
constructor(
@Optional() @Inject('HTTP_OPTIONS') private readonly httpClient: T
) {}
}
```
請注意,在上面的示例中,我們使用自定義 `provider`,這是我們包含 `HTTP_OPTIONS`自定義標記的原因。前面的示例顯示了基于構造函數的注入,通過構造函數中的類指示依賴關系。[在此處](/8/fundamentals)詳細了解自定義providers及其關聯的 `token`。
## 基于屬性的注入
我們目前使用的技術稱為基于構造函數的注入,即通過構造函數方法注入 providers。在某些非常特殊的情況下,基于屬性的注入可能會有用。例如,如果頂級類依賴于一個或多個 providers,那么通過從構造函數中調用子類中的 `super()` 來傳遞它們就會非常煩人了。因此,為了避免出現這種情況,可以在屬性上使用 `@Inject()` 裝飾器。
```typescript
import { Injectable, Inject } from '@nestjs/common';
@Injectable()
export class HttpService<T> {
@Inject('HTTP_OPTIONS')
private readonly httpClient: T;
}
```
> 如果您的類沒有擴展其他提供者,你應該總是使用基于**構造函數**的注入。
## 注冊提供者
現在我們已經定義了提供者(`CatsService`),并且已經有了該服務的使用者(`CatsController`),我們需要在 `Nest` 中注冊該服務,以便它可以執行注入。 為此,我們可以編輯模塊文件(`app.module.ts`),然后將服務添加到`@Module()`裝飾器的 `providers` 數組中。
> app.module.ts
```typescript
import { Module } from '@nestjs/common';
import { CatsController } from './cats/cats.controller';
import { CatsService } from './cats/cats.service';
@Module({
controllers: [CatsController],
providers: [CatsService],
})
export class AppModule {}
```
得益于此,`Nest` 現在將能夠解決 `CatsController` 類的依賴關系。這就是我們目前的目錄結構:
```
src
├── cats
│ ├──dto
│ │ └──create-cat.dto.ts
│ ├── interfaces
│ │ └──cat.interface.ts
│ ├──cats.service.ts
│ └──cats.controller.ts
├──app.module.ts
└──main.ts
```
## 手動實例化
到目前為止,我們已經討論了 Nest 如何自動處理解決依賴關系的大多數細節。在某些情況下,您可能需要跳出內置的依賴注入系統,并手動檢索或實例化提供程序。我們在下面簡要討論兩個這樣的主題。
要獲取現有實例或動態實例化提供程序,可以使用 [Module reference](https://docs.nestjs.com/fundamentals)。
要在 `bootstrap()` 函數內使用提供程序(例如,對于不帶控制器的獨立應用程序,或在引導過程中使用配置服務),請參見[獨立應用程序](https://docs.nestjs.com/standalone-applications)。
- 介紹
- 概述
- 第一步
- 控制器
- 提供者
- 模塊
- 中間件
- 異常過濾器
- 管道
- 守衛
- 攔截器
- 自定義裝飾器
- 基礎知識
- 自定義提供者
- 異步提供者
- 動態模塊
- 注入作用域
- 循環依賴
- 模塊參考
- 懶加載模塊
- 應用上下文
- 生命周期事件
- 跨平臺
- 測試
- 技術
- 數據庫
- Mongo
- 配置
- 驗證
- 緩存
- 序列化
- 版本控制
- 定時任務
- 隊列
- 日志
- Cookies
- 事件
- 壓縮
- 文件上傳
- 流式處理文件
- HTTP模塊
- Session(會話)
- MVC
- 性能(Fastify)
- 服務器端事件發送
- 安全
- 認證(Authentication)
- 授權(Authorization)
- 加密和散列
- Helmet
- CORS(跨域請求)
- CSRF保護
- 限速
- GraphQL
- 快速開始
- 解析器(resolvers)
- 變更(Mutations)
- 訂閱(Subscriptions)
- 標量(Scalars)
- 指令(directives)
- 接口(Interfaces)
- 聯合類型
- 枚舉(Enums)
- 字段中間件
- 映射類型
- 插件
- 復雜性
- 擴展
- CLI插件
- 生成SDL
- 其他功能
- 聯合服務
- 遷移指南
- Websocket
- 網關
- 異常過濾器
- 管道
- 守衛
- 攔截器
- 適配器
- 微服務
- 概述
- Redis
- MQTT
- NATS
- RabbitMQ
- Kafka
- gRPC
- 自定義傳輸器
- 異常過濾器
- 管道
- 守衛
- 攔截器
- 獨立應用
- Cli
- 概述
- 工作空間
- 庫
- 用法
- 腳本
- Openapi
- 介紹
- 類型和參數
- 操作
- 安全
- 映射類型
- 裝飾器
- CLI插件
- 其他特性
- 遷移指南
- 秘籍
- CRUD 生成器
- 熱重載
- MikroORM
- TypeORM
- Mongoose
- 序列化
- 路由模塊
- Swagger
- 健康檢查
- CQRS
- 文檔
- Prisma
- 靜態服務
- Nest Commander
- 問答
- Serverless
- HTTP 適配器
- 全局路由前綴
- 混合應用
- HTTPS 和多服務器
- 請求生命周期
- 常見錯誤
- 實例
- 遷移指南
- 發現
- 誰在使用Nest?