likes
comments
collection
share

神光《Nest 通关秘籍》学习总结-全局模块和生命周期详解

作者站长头像
站长
· 阅读数 44

最近在学习神光大神的《Nest通关秘籍》,该小册主要包含下面这些内容:

神光《Nest 通关秘籍》学习总结-全局模块和生命周期详解 想购买的可以点击《传送门》。

接下来的日子里,我将更新一系列的学习笔记。感兴趣的可以关注我的专栏《Nest 通关秘籍》学习总结

特别申明:本系列文章已经经过作者本人的允许。 大家也不要想着白嫖,我的笔记只是个人边学习边记录的,不是很完整,大家想要深入学习还是要自己去购买原版小册。

本章我们来学习nest中的全局模块和生命周期。

全局模块

搞一个 nest 项目:

nest new global-and-lifecycle -p pnpm

首先,想在一个模块中引入另一个模块需要怎么做呢?

创建两个 CURD 的模块:

nest g resource aaa --no-spec
nest g resource bbb --no-spec

在 AaaModule 里指定 exports 的 provider:

import { Module } from '@nestjs/common';
import { AaaService } from './aaa.service';
import { AaaController } from './aaa.controller';

@Module({
  controllers: [AaaController],
  providers: [AaaService],
  exports: [AaaService],
})
export class AaaModule {}

然后在 BbbModule 里 imports:

import { Module } from '@nestjs/common';
import { BbbService } from './bbb.service';
import { BbbController } from './bbb.controller';
import { AaaModule } from 'src/aaa/aaa.module';
@Module({
  imports: [AaaModule],
  controllers: [BbbController],
  providers: [BbbService],
})
export class BbbModule {}

这样就可以在 BbbModule 内注入 AaaService 了:

import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common';
import { BbbService } from './bbb.service';
import { AaaService } from '../aaa/aaa.service';
@Controller('bbb')
export class BbbController {
  constructor(
    private readonly bbbService: BbbService,
    private readonly aaaService: AaaService,
  ) {}

  @Get()
  findAll() {
    return 'this action is bbb ' + this.aaaService.findAll();
  }
}

这是我们常用的引入 Module 的方式。

但如果这个 AaaModule 被很多地方引用呢?

每个模块都需要 imports 太麻烦了,这时候就可以使用Global把它声明为全局的:

import { Module, Global } from '@nestjs/common';
import { AaaService } from './aaa.service';
import { AaaController } from './aaa.controller';

@Global() // 声明为全局
@Module({
  controllers: [AaaController],
  providers: [AaaService],
  exports: [AaaService],
})
export class AaaModule {}

然后在B模块中把imports去掉:

import { Module } from '@nestjs/common';
import { BbbService } from './bbb.service';
import { BbbController } from './bbb.controller';
@Module({
  imports: [],
  controllers: [BbbController],
  providers: [BbbService],
})
export class BbbModule {}

这样依然可以在B模块中引入A模块了。

像上面这样使用Global声明得就是全局模块。

现在我们来看看个个模块之间引用的流程图:

神光《Nest 通关秘籍》学习总结-全局模块和生命周期详解

我大概画了这么一张图:

  • 首先在App.module中引入Aaa.moduleBbb.module。这样才能把这两个模块注入IOC容器中。
  • Aaa.module中exports了一个Aaa.service,就是是把它的Provider暴露出来了,这里的Provider我们指的是Aaa.service中的方法。
  • 然后在Bbb.module中imports了一下Aaa.module,也就是把Aaa.service中方法引入进来了。
  • 最后我们就可以在Bbb.controller中使用Aaa.service的方法了。

生命周期

应用初始化的时候生命周期:

神光《Nest 通关秘籍》学习总结-全局模块和生命周期详解

在整个初始化生命周期中,nest是这样执行的:首先,Nest在初始化的会先递归Module依赖模块,会依次调用模块内的 controller、provider 的 onModuleInit 方法,然后再调用 module 的 onModuleInit 方法。

全部初始化完之后,再依次调用模块内的 controller、provider 的 onApplicationBootstrap 方法,然后调用 module 的 onApplicationBootstrap 方法然后监听网络端口。之后 Nest 应用就正常运行了。

应用销毁的时候生命周期:

神光《Nest 通关秘籍》学习总结-全局模块和生命周期详解

在整个销毁的声明周期中,先调用每个模块的 controller、provider 的 onModuleDestroy 方法,然后调用 Module 的 onModuleDestroy 方法。

之后再调用每个模块的 controller、provider 的 beforeApplicationShutdown 方法,然后调用 Module 的 beforeApplicationShutdown 方法。然后停止监听网络端口。之后调用每个模块的 controller、provider 的 onApplicationShutdown 方法,然后调用 Module 的 onApplicationShutdown 方法。之后停止进程。

下面我们在代码中实际看看。

首先我们新建一个ccc模块:

nest g resource ccc --no-spec

然后在对应的controller、service、module里分别添加下面几个生命周期函数:

  • OnModuleInit
  • OnApplicationBootstrap
  • OnModuleDestroy
  • BeforeApplicationShutdown
  • OnApplicationShutdown

ccc.module.ts文件:

import {
  Module,
  OnModuleInit,
  OnApplicationBootstrap,
  OnModuleDestroy,
  BeforeApplicationShutdown,
  OnApplicationShutdown,
} from '@nestjs/common';
import { CccService } from './ccc.service';
import { CccController } from './ccc.controller';

@Module({
  controllers: [CccController],
  providers: [CccService],
})
export class CccModule
  implements
    OnModuleInit,
    OnApplicationBootstrap,
    OnModuleDestroy,
    BeforeApplicationShutdown,
    OnApplicationShutdown
{
  onModuleInit() {
    console.log('CccModule OnModuleInit');
  }

  onApplicationBootstrap() {
    console.log('CccModule OnApplicationBootstrap');
  }

  onModuleDestroy() {
    console.log('CccModule onModuleDestroy');
  }

  beforeApplicationShutdown() {
    console.log('CccModule beforeApplicationShutdown');
  }

  onApplicationShutdown() {
    console.log('CccModule onApplicationShutdown');
  }
}

ccc.controller.ts文件:

import {
  Controller,
  OnModuleInit,
  OnApplicationBootstrap,
  OnModuleDestroy,
  BeforeApplicationShutdown,
  OnApplicationShutdown,
} from '@nestjs/common';
import { CccService } from './ccc.service';

@Controller('ccc')
export class CccController
  implements
    OnModuleInit,
    OnApplicationBootstrap,
    OnModuleDestroy,
    BeforeApplicationShutdown,
    OnApplicationShutdown
{
  constructor(private readonly cccService: CccService) {}

  onModuleInit() {
    console.log('CccController OnModuleInit');
  }

  onApplicationBootstrap() {
    console.log('CccController OnApplicationBootstrap');
  }

  onModuleDestroy() {
    console.log('CccController onModuleDestroy');
  }

  beforeApplicationShutdown() {
    console.log('CccController beforeApplicationShutdown');
  }

  onApplicationShutdown() {
    console.log('CccController onApplicationShutdown');
  }
}

ccc.service.ts文件:

import {
  Injectable,
  OnModuleInit,
  OnApplicationBootstrap,
  OnModuleDestroy,
  BeforeApplicationShutdown,
  OnApplicationShutdown,
} from '@nestjs/common';

@Injectable()
export class CccService
  implements
    OnModuleInit,
    OnApplicationBootstrap,
    OnModuleDestroy,
    BeforeApplicationShutdown,
    OnApplicationShutdown
{
  onModuleInit() {
    console.log('CccService OnModuleInit');
  }

  onApplicationBootstrap() {
    console.log('CccService OnApplicationBootstrap');
  }

  onModuleDestroy() {
    console.log('CccService onModuleDestroy');
  }

  beforeApplicationShutdown() {
    console.log('CccService beforeApplicationShutdown');
  }

  onApplicationShutdown() {
    console.log('CccService onApplicationShutdown');
  }
}

首先我们来看看初始化的时候,声明周期执行的顺序:

神光《Nest 通关秘籍》学习总结-全局模块和生命周期详解

从打印的日志可以看出来执行顺序大概如下:

  1. controller的onModuleInit执行
  2. service的onModuleInit执行
  3. module的onModuleInit执行
  4. controller的onApplicationBootstrap执行
  5. service的onApplicationBootstrap执行
  6. module的onApplicationBootstrap执行

接下来我们在main.ts中添加一个定时器,调用app.close()来触发销毁的生命周期:

// main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
  setTimeout(() => {
    // app.close();
  }, 3000);
}
bootstrap();

神光《Nest 通关秘籍》学习总结-全局模块和生命周期详解

可以看到,它的执行顺序是这样的:

  1. controller的onModuleDestroy执行
  2. service的onModuleDestroy执行
  3. module的onModuleDestroy执行
  4. controller的beforeApplicationShutdown执行
  5. service的beforeApplicationShutdown执行
  6. module的beforeApplicationShutdown执行
  7. controller的onApplicationShutdown执行
  8. service的onApplicationShutdown执行
  9. module的onApplicationShutdown执行

以上就是Nest所有的生命周期函数,一共有五个。

转载自:https://juejin.cn/post/7242163788039634999
评论
请登录