gpt4 book ai didi

【NestJS系列】DI依赖注入与IOC控制反转

转载 作者:我是一只小鸟 更新时间:2023-07-17 14:31:47 26 4
gpt4 key购买 nike

前言

上篇文章我们学习了如何使用 nest-cli 来快速生成一个 NestJS 后端项目,当我们打开编辑器查看代码时,会发现整个代码风格有点类似JAVA的 spring 框架,并且你会发现一些 service 类在 controller 控制器的 constructor 中注入后,可以不需要手动 new 就可以直接使用该类对应的实例方法.

比如:

                        
                          import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get('/hello')
  get(): string {
    return this.appService.getHello();
  }
}

                        
                      

这其实就是 Nest 依赖注入与控制反转,目的主要是方便代码之间的解耦从而减少维护成本.

什么是依赖注入(DI)与控制反转(IOC)

这两个概念不要搞混了,IOC其实是面向对象编程中的一种设计模式,而DI则是为了实现IOC的一种技术.

传统耦合代码

比如,我们有两个类,它们之间存在耦合关系,我们一般会这样写:

                        
                          // A.ts
class A {
  name: string
  constructor(name: string) {
    this.name = name
  }
}

// B.ts
class B {
  age: number
  name: A
  constructor(age: number) {
    this.age = age
    this.name = new A('南玖')
  }
}

// main.ts
const b = new B(18)
console.log(b)

                        
                      

当我们遇到类与类之间存在依赖关系时,一般会直接在类的内部创建依赖对象,这样就会导致各个类之间形成耦合,并且这种关系会随着依赖关系越来越复杂从而耦合度也会越来越高,最终造成代码的难以维护.

简易版IOC

为了解决上面代码带来的耦合性问题,我们可以使用IOC容器来进行管理 。

                        
                          // container.ts
export class Container {
  modules = new Map()
  
  // 注册实例
  provide(key: string, clazz: any, argvs: Array<any>) {
    this.modules.set(key, {clazz, argvs})
  }
  // 获取实例
  get(key: string) {
    const {clazz, argvs} = this.modules.get(key)
    return Reflect.construct(clazz, argvs)
  }
}

                        
                      

这里的 Reflect.construct 是为了帮我们实例化一个对象.

以上就是容器化思路,统一管理,可以实现类与类之间的解耦.

Nest JS的IOC与DI

依赖注入是一种控制反转 IOC(inversion of control) 技术,就是你可以把对象或依赖的实例化交给 IOC 容器去处理,在 NestJS 中这个容器就是 NestJS 的运行时系统。当需要一个对象实例的时候,我们不需要自己手动 new xxxClass() ,只需要在合适的地方对类进行注册,在需要用到的地方直接注入,容器将为我们完成 new 的动作 。

在 Nest 中使用依赖注入一般有以下三步:

声明定义

使用 @Injectable 装饰器来声明一个类,它表示该类可以由 Nest 的 IOC 容器管理 。

                        
                          // app.service.ts
import { Injectable } from '@nestjs/common';

@Injectable()
export class AppService {
  getHello(): string {
    return 'Hello nanjiu';
  }
}

                        
                      

声明在什么地方使用

这是依赖注入的地方,一般是在类的构造函数 constructor 中注入,只有完成注入后才可以使用 。

                        
                          // app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  @Get('/hello')
  get(): string {
    return this.appService.getHello();
  }
}


                        
                      

官方把 appService 称为 token , NestJS 会根据这个 token 在容器中找到第1步中声明的类(这个对应关系将在第三步中进行关联注册),从而提供对应的实例,这里的实例全局唯一,只有1个!在第一次需要该实例的时候, Nest 会 new 一个出来,而后会缓存起来,后序如果其它地方也注入了这个依赖,那 Nest 会从缓存中拿到之前 new 出来的实例供大家使用.

建立注入依赖与容器中类的联系

依赖注入后还需要在 Module 中进行关联 。

                        
                          import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}


                        
                      

Nest 会根据所有注入的依赖关系生成一个依赖关系图,就有点类似我们使用 import 引入各个模块时也会生成一个复杂的依赖关系图。这里 AppController 中依赖了 AppService ,如果 AppService 中还依赖其它东西也会一并放到 Nest 构建的依赖关系图中, Nest 会从下到上按照依赖顺序构建出一整张依赖关系图保证所有的依赖关系正常运作.

最后此篇关于【NestJS系列】DI依赖注入与IOC控制反转的文章就讲到这里了,如果你想了解更多关于【NestJS系列】DI依赖注入与IOC控制反转的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com