首页 > 其他分享 >【NestJS系列】DI依赖注入与IOC控制反转

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

时间:2023-07-29 21:05:55浏览次数:38  
标签:AppService 依赖 DI Nest NestJS new import IOC

前言

上篇文章我们学习了如何使用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装饰器来声明一个类,它表示该类可以由NestIOC容器管理

// 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称为tokenNestJS会根据这个token在容器中找到第1步中声明的类(这个对应关系将在第三步中进行关联注册),从而提供对应的实例,这里的实例全局唯一,只有1个!在第一次需要该实例的时候,Nestnew一个出来,而后会缓存起来,后序如果其它地方也注入了这个依赖,那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会从下到上按照依赖顺序构建出一整张依赖关系图保证所有的依赖关系正常运作。

标签:AppService,依赖,DI,Nest,NestJS,new,import,IOC
From: https://blog.51cto.com/u_13756259/6895128

相关文章

  • 【NestJS系列】核心概念:Providers提供者
    前言Providers是Nest中的一个基本概念,许多Nest中定义的类都可以被视为一个Provider,比如:service、repository、factory、helper等,它们都可以通过constructor注入依赖关系,这就意味着类与类之间可以创建各种依赖关系,并且维护各个类之间依赖关系的工作将委托给Nest运行时系统。Provider......
  • Educational Codeforces Round 152 (Rated for Div. 2)
    传送阵T1MorningSandwich题目大意\(t\)个测试,每个测试给三个正整数\(b,c,h\),分别表示面包和两种馅料的个数,每两个面包之间必须放一个馅料,问最多能摆几层?思路我们发现\(c,h\)所表示的两种馅料其实相差不大,所以我们可以分两种情况\(a>c+h\)因为开头总是面包,所以要+......
  • Android studio 4.1.2安装入门教程
    目录JDK安装与配置一、下载JDK二、JDK安装三、JDK的环境配置四、JDK的配置验证Androidstudio安装Androidstudio连接手机真机调试(以华为鸿蒙为例)一、新建一个android项目二、进入项目面板三、配置AndroidStudio四、安装手机驱动程序五、连接手机六、运行程序七、......
  • 【NestJS系列】从Nest CLI开始入门
    初识NestJSNest是一个渐进的Node.js框架,它可以在TypeScript和JavaScript(ES6、ES7、ES8)之上构建高效、可伸缩的企业级服务器端应用程序。Nest基于TypeScript编写并且结合了OOP(面向对象编程),FP(函数式编程)和FRP(函数式响应编程)的相关理念。在设计上的很多灵感来自于Ang......
  • Codeforces Round 888 (Div. 3)
    CodeforcesRound888(Div.3)T1​ 思路:直接模拟。T2​思路:首先记录原始数组的奇偶性,然后将奇数、偶数分为不同两组进行排序,然后再根据原数组的奇偶性按顺序填入奇数偶数,最后判断整个数组是否非递减。T3思路:我们已知开始在\(a_1\),最后在\(a_n\)。那么当\(a_1\ne......
  • Educational Codeforces Round 152 (Rated for Div. 2) 题解
    \(6\)题做出来\(3\)题,这一次的D题没能复刻上一次Round888Div.3最后几分钟AC的奇迹A.MorningSandwich大水题,5min时间4min都在翻译题面直接拿\(b\)和\(c+h\)进行比较分类讨论即可单次操作时间复杂度\(O(1)\)B.Monsters首先有一个特别显然、复杂度特别高的......
  • Huggingface | 修改模型的embedding
    目标:在NLP领域,基于公开语料的预训练模型,在专业领域迁移时,会遇到专业领域词汇不在词汇表的问题,本文介绍如何添加专有名词到预训练模型。NLP的处理流程:对输入的句子进行分词,得到词语及下标通过embedding层获得词语对应的embeddingembedding送入到预训练模型,经过attention注意......
  • 无涯教程-jQuery - Accordion组件函数
    小部件手风琴功能可与JqueryUI中的小部件一起使用。手风琴与Tabs相同,当用户单击标题以展开分成逻辑部分的内容时,Accordion与Tabs相同。Accordion-语法这是使用手风琴的简单语法-$(function(){$("#accordion").accordion();});Accordion-示例以下是显示手风琴用......
  • gdb 反汇编disas源码排列问题
    问题在开发过程中,可能需要查看cpp文件生成的汇编代码来确认一些问题。由于单纯的汇编代码看起来并不太容易捋清楚内部逻辑,所以最好能够把源代码的位置列出来。在gdb的早期版本中,这个功能是通过disas命令的/m修饰符(选项)来实现的。如果使用过这个选项就会发现,这个功能显示的结果......
  • python的tril,pad,block_diag在LLM上的使用
    最近需要对position_ids和attention_mask进行重构,所以需要掌握numpy的一些操作,以下是一些示例,多个下三角矩阵拼接:importnumpyasnpfromscipy.linalgimportblock_diagA=np.ones((2,2))B=np.ones((3,3))b=[A,B]print(np.tril(block_diag(*b)))[[1.0.0.0.0.]......