【Nestjs实操】服务依赖注入

news2024/11/15 8:25:55

在开始学习之前,我们首先准备下开发环境:

  • Node:16.20.2
  • 包管理器:pnpm
  • nestjs版本:10.2.1
  • 全局安装nestjs命令行:pnpm add -g @nestjs/cli

一、初始化项目

执行nest new nestjs-blog,系统会自动创建一个nestjs项目,并安装好好所有依赖项目。

image-20240309102023372

初始的项目目录结构如下:

image-20240309102445492

然后我们执行pnpm start:dev启动项目,访问localhost:3000,就可以看到项目已经正常启动。

image-20240309102832939

文件说明:

  • /src/main:项目入口文件。用于启动整个项目,可以配置
  • /src/app.module.ts:模块。整个项目可以划分为多个独立的模块,作为每个模块的入口文件,负责引入其他模块、注入服务、导出服务、配置控制器。app.module.ts作为整个项目的基石模块,还负责引入项目中所有的模块、服务、控制器。
  • /src/app.service.ts:服务。用于存放本模块中的所有业务逻辑
  • /src/app.controller.ts:控制器。用于配制路由、鉴权、入参、返回数据等

二、依赖注入

1、服务注入

最常见的就是本模块中的服务,在模块中注入,然后在控制器中声明并引用。这里就拿app.module.ts文件举例:

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

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],//注入AppService服务
})
export class AppModule {}
//app.controller.ts
import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  //在构造函数中直接声明
  constructor(private readonly appService: AppService) {}

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
}
//app.service.ts
import { Injectable } from '@nestjs/common';
//服务中必须要使用Injectable装饰器,声明此服务可以被注入
@Injectable()
export class AppService {
  getHello(): string {
    return 'Hello World!';
  }
}

2、自定义服务名称

app.module.ts文件中,注入服务时,上面的方式是直接在providers中配置服务类型就可以了,系统会自动到 服务注册容器 中去检索对应的服务。如下:

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],//直接写服务类名称
})

完整的写法是这样的:

@Module({
  imports: [],
  controllers: [AppController],
  providers: [{
    provide: AppService,	//声明服务名称
    useValue: new AppService(),//声明服务使用的服务类
  }],
})

当然我们也可以自定义服务名,如下:

//app.module.ts
@Module({
  imports: [],
  controllers: [AppController],
  providers: [{
    provide: "app",//这里改成字符串名称
    useValue: new AppService(),
  }],
})

//app.controller.ts
export class AppController {
  constructor(@Inject("app") private readonly appService: AppService) { }

  ...
}

可以看到在app.module.ts中声明了服务字符串名称:provide: "app",然后在控制器中调用时,就需要在构造函数入参中添加@Inject("app")

3、注入自定义数据

useValue中返回的数据可以是自定义的任何数据。

//app.module.ts
@Module({
  imports: [],
  controllers: [AppController],
  providers: [{
    provide: "app",
    useValue: { name: "IT飞牛" },//自定义数据
  }],
})

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

@Controller()
export class AppController {
  constructor(@Inject("app") private readonly appService: any) { }

  @Get()
  getHello(): string {
    return this.appService.name;//返回自定义数据中的属性值
  }
}

再次访问页面localhost:3000,页面显示如下:

image-20240309130802190

4、使用工厂函数注入服务

有些场景下,我们需要根据条件动态引入服务,这时候我们可以借助useFactory工厂函数,来动态加载。

//app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';

//配置服务
const configService = {
  provide: "config",
  useValue: { url: "11.22.33.44" },
}

@Module({
  imports: [],
  controllers: [AppController],
  providers: [configService, {
    provide: "app",
    inject: ["config"],//引入配置服务config,这样可以给useFactor作为入参使用
    useFactory: (config) => {
        //合并config配置服务,并且追加appUrl属性。
      return {
        ...config,
        appUrl: "itfeiniu.com"
      }
    }
  }],
})
export class AppModule { }

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

@Controller()
export class AppController {
  constructor(@Inject("app") private readonly appService: any) { }

  @Get()
  getHello(): string {
      //appService服务实例中,使用useFactory引入时,混合了config和自定义追加的appUrl。这里都可以调用。
    return "url:" + this.appService.url + " <br/> appUrl:" + this.appService.appUrl;
  }
}

使用工厂函数来动态加载服务时,我们可以使用injest引入其他服务,然后就可以在工厂函数中写业务逻辑,返回我们需要的服务数据。上述例子中,app

服务最终返回的是:

{
    url: "11.22.33.44",
    appUrl: "itfeiniu.com"
}

所有我们在控制器中可以直接调用。

工厂函数常见用于,根据环境变量的不同,动态引入不同环境下对应的服务数据。

5、异步引入服务

服务在注册的时候,我们也可以使用异步引入,useFactory工厂函数返回一个Promise对象。具体如下:

//app.module.ts
@Module({
  imports: [],
  controllers: [AppController],
  providers: [configService, {
    provide: "app",
    inject: ["config"],
    useFactory: async (config) => {
        //返回一个Promise对象
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve({
            ...config,
            appUrl: "itfeiniu.com"
          });
        }, 3000);
      })
    }
  }],
})

通过后端服务运行日志,可以看到,服务加载耗时3s

image-20240309133104475

6、共享服务

一个服务,我们有时候需要在不同的模块中使用,那么就需要使用服务共享。

  • 创建一个test服务,执行如下代码,创建test.module.tstest.service.ts文件:

    nest g mo test
    nest g s test --no-spec
    

    创建后,会自动引入app.module.ts

    image-20240309140354881

  • test.service.ts代码

    import { Injectable } from '@nestjs/common';
    
    @Injectable()
    export class TestService {
        constructor() { }
        getTest(): string {
            return 'Hello Test!';
        }
    }
    
  • test.module.ts代码

    import { Module } from '@nestjs/common';
    import { TestService } from './test.service';
    
    @Module({
        providers: [TestService],
        exports: [TestService]//不光要在app.module.ts的import中引入,还需要在这里导出
    })
    export class TestModule { }
    
  • app.module.ts代码:

    @Module({
      imports: [TestModule],//使用nest g s test命令行创建后,会自动添加;否则需要手动添加。
      controllers: [AppController],
      ...
    })
    
  • app.controller.ts代码:

    import { Controller, Get, Inject } from '@nestjs/common';
    import { TestService } from './test/test.service';
    
    @Controller()
    export class AppController {
      constructor(private testService:TestService) { }
    
      @Get()
      getHello(): string {
        return this.testService.getTest();//调用test服务中的getTest方法,返回:Hello Test!
      }
    }
    

配置完上述代码,我们再次访问:localhost:3000页面如下:

image-20240309140911471

三、支持环境变量

1、使用dotenv

  • 安装pnpm add dotenv

  • 根目录下创建.env文件,内容如下:

NODE_ENV=development
  • 使用
import {config} from "dotenv";
const path = require('path');
config({path:path.join(__dirname,'../.env')});
console.log(process.env.NODE_ENV);//读取

2、使用corss-env

  • 全局安装cross-env,执行:pnpm add cross-env -g

  • 调整package.json中的script配置:

  "scripts": {
    "start:dev": "cross-env APIHOST=itfeiniu.com nest start --watch",
      ...
  },
  • 如何使用:process.env.APIHOST

以上两种环境变量的方式,可以同时存在。

image-20240309134956428

不用的import对象,可以使用shift+alt+o自动整理清除。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1502727.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

关于 JVM

1、请你谈谈你对JVM的理解&#xff1f; JVM由JVM运行时数据区&#xff08;图示中蓝色框包含部分&#xff09;、执行引擎、本地库接口、本地方法库组成。 JVM运行时数据区&#xff0c;分为方法区、堆、虚拟机栈、本地方法栈和程序计数器。 1.方法区 Java 虚拟机规范中定…

黑马点评-异步秒杀实现

异步秒杀思路 我们来回顾一下下单流程 当用户发起请求&#xff0c;此时会请求nginx&#xff0c;nginx会访问到tomcat&#xff0c;而tomcat中的程序&#xff0c;会进行串行操作&#xff0c;分成如下几个步骤 1、查询优惠卷 2、判断秒杀库存是否足够 3、查询订单 4、校验是…

Draco点云压缩测试

ref&#xff1a;https://github.com/google/dracohttps://codelabs.developers.google.com/codelabs/draco-3d/index.html#6 Draco Draco 是一个用于编码压缩和解压缩 3D 几何网格和点云的库&#xff0c;从而改进 3D 图形的存储和传输该代码支持压缩点、连接信息、纹理坐标、颜…

个人代码分享(底层模板函数和三大模板)2024.3.6

源码&#xff1a;&#xff08;百度网盘&#xff09; 链接&#xff1a;https://pan.baidu.com/s/1jdfrQOGCWJaQgSUPEWcfdw?pwd1234 提取码&#xff1a;1234 说明&#xff1a; 从复习到应用所有学到的东西去做真题&#xff0c;笔者对于之前发过的文章里面的代码有着很多改动&…

用msvc编译器的cl.exe将gcc编译器的.s汇编文件转masm编译器的.asm文件

用msvc编译器的cl.exe将gcc编译器的.s汇编文件转masm编译器的.asm文件 cl /nologo /X /II:/code/reactos-master/sdk/include/asm /II:/code/reactos-master/output-VS-amd64-sln/sdk/include/asm -II:/code/reactos-master/sdk/include -II:/code/reactos-master/sdk/include…

051-WEB攻防-前后台功能点文件下载文件读取文件删除目录遍历目录穿越

051-WEB攻防-前后台功能点&文件下载&文件读取&文件删除&目录遍历&目录穿越 #知识点&#xff1a; 1、文件安全-前后台功能点-下载&读取&删除 2、目录安全-前后台功能点-目录遍历&目录穿越 演示案例&#xff1a; ➢文件安全-下载&删除-案例…

Centos 安装 redis【最简单】

Centos7 使⽤ yum 安装 ⾸先安装 scl 源, 再安装 redis &#xff08;因为 Centos7 yum 提供的软件包只有 3.0 版本的 Redis &#xff0c;太老了&#xff0c;我们要安装 redis 5 系列的&#xff09; yum install centos-release-scl-rh yum install rh-redis5-redis 创建符号…

阿里云99计划优惠:云服务器租用价格61元、99元、165元

阿里云99计划还有谁不知道么&#xff1f;阿里云不杀熟&#xff0c;新老用户同享&#xff0c;阿里云服务器99元一年&#xff0c;续费也是99元&#xff0c;续费不涨价家人们&#xff0c;2024年阿里云把云服务器价格打下来了&#xff0c;2核2G、2核4G、4核8G、4核16G、8核16G、8核…

《在“裸奔”时代下如何保护网络隐私》

引言 在信息时代的今天,网络已经成为我们生活中不可或缺的一部分。然而,随着网络的普及和技术的发展,网络安全和隐私保护问题也变得越来越严峻。特别是在这个所谓的“裸奔”时代,我们的个人信息和隐私正面临着前所未有的挑战。因此,保护网络隐私变得尤为重要。 网络安全…

吴恩达deeplearning.ai:机器学习的开发过程与优化方法

以下内容有任何不理解可以翻看我之前的博客哦&#xff1a;吴恩达deeplearning.ai专栏 我想在接下来分析下开发机器学习系统的过程&#xff0c;这样当你自己动手时&#xff0c;能够做出更加正确的判断。 机器学习开发的迭代 Iterative loop of ML development 决定模型架构 第…

flink实战--Flink任务资源自动化优化

背景 在生产环境Flink任务资源是用户在实时平台端进行配置,用户本身对于实时任务具体配置多少资源经验较少,所以存在用户资源配置较多,但实际使用不到的情形。比如一个 Flink 任务实际上 4 个并发能够满足业务处理需求,结果用户配置了 16 个并发,这种情况会导致实时计算资…

【uniapp】uniapp小程序中实现拍照同时打开闪光灯的功能,拍照闪光灯实现

一、需求前提 特殊场景中&#xff0c;需要拍照的同时打开闪光灯&#xff0c;&#xff08;例如黑暗场景下的设备维护巡检功能&#xff09;。 起初我是用的uviewui中的u-upload组件自带的拍照功能&#xff0c;但是这个不支持拍照时打开闪光灯&#xff0c;也不支持从通知栏中打开…

哈希表应用

例题 在这里使用一个简化版的问题进行分析&#xff1a;给定N个自然数&#xff0c;值域是&#xff0c;求出这N个自然数中共有多少个不同的自然数。 分析 如果值域是&#xff0c;那么可以利用之前介绍过的计数排序算法解决问题。定义一个的大数组a&#xff0c;每个位置a[x]所对…

vue 使用 PrintJs 实现打印pdf效果

一、print.js介绍 Print.js主要是为了帮助我们直接在应用程序中打印PDF文件&#xff0c;而无需离开界面&#xff0c;并且不使用嵌入。对于用户不需要打开或下载PDF文件的特殊情况&#xff0c;他们只需要打印它们。 例如&#xff0c;当用户请求打印在服务器端生成的报告时&…

Spring web MVC(入门)

1、什么是MVC&#xff08;一种思想&#xff09; Model View Controller &#xff1a; Model—模型 View—视图 Controller—控制器 2、Spring MVC是一种实现&#xff08;我们现在学的是Spring web,Spring mvc过时了&#xff09; View属于前端问题我们后端人员不必太过于关注…

Java基础 - 8 - 算法、正则表达式、异常

一. 算法 什么是算法&#xff1f; 解决某个实际问题的过程和方法 学习算法的技巧&#xff1f; 先搞清楚算法的流程&#xff0c;再直接去推敲如何写算法 1.1 排序算法 1.1.1 冒泡排序 每次从数组中找出最大值放在数组的后面去 public class demo {public static void main(S…

JVM——执行引擎

文章目录 1、概述2、计算机语言的发展史2.1、机器码2.2、汇编语言2.3、高级语言2.4、字节码 3、Java代码编译和执行过程4、解释器5、JIT编译器5.1、为什么HotSpot VM同时存在JIT编译器和解释器5.2、热点代码探测确定何时JIT5.3、设置执行模式5.4、C1编译器和C2编译器 6、AOT编译…

python实现桶排序

桶排序&#xff08;Bucket Sort&#xff09;是一种排序算法&#xff0c;它将待排序的元素分到有限数量的桶&#xff08;buckets&#xff09;中&#xff0c;然后分别对每个桶中的元素进行排序&#xff0c;最后按照顺序将所有的桶中的元素依次取出&#xff0c;即可得到有序序列。…

深入了解Kafka中Topic的神奇之处

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 深入了解Kafka中Topic的神奇之处 前言Topic的基本概念Kafka Topic 的定义&#xff1a;Kafka Topic 的基本原理&#xff1a;为何 Topic 是 Kafka 消息传递的核心组成部分&#xff1a; 创建和配置Topic创…

FairScale 库测试实验(一)-- 大模型训练基础之模型并行

DDP的分布式训练方法采用数据并行方式&#xff0c;相当于通过增大数据的batch来加快训练。但对于大模型&#xff08;LLM&#xff09;来说&#xff0c;DDP已经不适用了。因为LLMs的模型本身太大&#xff0c;一块GPU都放不下怎么可能去复制从而实现数据并行呢。所以LLM的训练采用…