nest 依赖注入

时间:2023-01-10 浏览:181 分类:NestJS

依赖注入是一种控制反转 (IoC) 技术,可以将依赖项的实例化委托给 IoC 容器创建(在我们的例子中是 NestJS 运行时系统),而不是在自己的代码中手动的创建实例。依赖注入主要用于类与类之间的依赖关系,实现松耦合,以便于后期开发测试。

理解依赖注入:

在没有使用依赖注入之前,如果有两个类Player 和 Weapon,如果Player 类需要使用Weapon类中的方法(及player依赖于weapon),通常方法是在player 类中手动创建weapon类的实例,然后再引入weapon类中的方法,如下:

class Player{  
    weapon;  

    constructor(){  
        // 手动创建实例 与 Sword类紧密耦合
        this.weapon = new Sword();  

    }  

    attack():void {
        this.weapon.attack();
    }
}

这样做的结果是weapon类和player类高度耦合,项目庞大时一处修改得处处修改,不利于后期维护和测试。

当引入依赖注入后,同样的问题,当player需要使用weapon类中的方法时,无需再手动创建weapon实例,而是将这个任务交给IoC 容器,由IoC 容器创建后以constructor注入方式引入,这样达到解耦的效果,如下:

import {Weapon} from “Weapon”;

class Player{  
    //在构造函数中注入依赖
    constructor(private readonly weapon: Weapon) {
    } 

    attack():void {
        this.weapon.attack();
    }
}

nest 中的依赖注入

首先,我们定义一个提供者。 @Injectable() 装饰器将 UserService 类标记为提供者。

// user.service.ts

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

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

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

然后我们请求 Nest 将提供者注入我们的控制器类:

//user.controller.ts

import { Controller, Get } from '@nestjs/common';
import { UserService } from './user.service';

@Controller('users')
export class CatsController {
  constructor(private userService: UserService) {}

  @Get()
  async findAll(): Promise<Cat[]> {
    return this.userService.findAll();
  }
}

最后,我们向 Nest IoC 容器注册提供者:

//user.module.ts

import { Module } from '@nestjs/common';
import { UserController } from './user.controller';


@Module({
  controllers: [UserController],
  providers: [UserService],
})
export class UserModule {}

幕后到底发生了什么使这项工作成功?整个过程分为三个关键步骤:

  1. 第一步:在 user.service.ts 中,@Injectable() 装饰器将 UserService 类声明为可由 Nest IoC 容器管理的类。

  2. 第二步:在 user.controller.ts 中,UserController 通过构造函数注入声明对 UserService 令牌的依赖:

  3. 第三步:在 user.module.ts 中,我们将令牌 UserService 与 user.service.ts 文件中的类 UserService 相关联。我们将在下面确切地看到这种关联(也称为注册)是如何发生的。

当 Nest IoC 容器实例化 UserController 时,它首先查找存在的任何依赖项 *。当它找到 UserService 依赖项时,它会根据注册步骤(上面的第3步)对 UserService 令牌执行查找,返回 UserService 类。假设 SINGLETON (单例)范围(默认行为),Nest 将创建一个 UserService 实例,缓存它并返回它,或者如果已经缓存了一个实例,则返回现有实例。


*这个解释有点简化以说明这一点。我们忽略的一个重要领域是分析代码依赖关系的过程非常复杂,并且发生在应用程序引导期间。一个关键特性是依赖分析(或“创建依赖图”)是可传递的。在上面的示例中,如果 UserService 本身具有依赖项,那么这些依赖项也会被解析。依赖关系图确保以正确的顺序解决依赖关系——本质上是“自下而上”。这种机制使开发人员不必管理如此复杂的依赖关系图。