Skip to content

全局模块和生命周期

全局模块

首先,我们来看看引入 Module 的方式。

创建两个 CRUD 的模块:

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

aaa.module.ts 中导出 Service:

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

bbb.module.ts 中导入 Module:

ts
@Module({
  imports: [AaaModule],
  controllers: [BbbController],
  providers: [BbbService],
})
export class BbbModule {}

bbb.service.ts 中注入 AaaService:

ts
@Injectable()
export class BbbService {
  constructor(private aaaService: AaaService) {}

  findAll() {
    return `This action returns all bbb` + this.aaaService.findAll()
  }
}

可以看到,Aaa 的服务已经生效了。

如果一个 Module 被很多的地方同时引用,每个模块都 imports 太麻烦了。这时考虑使用全局模块。声明方法很简单,在 aaa.module.ts 中 加上 Global 装饰器即可:

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

bbb.module.ts 里把 AaaService 删掉:

ts
@Module({
  imports: [],
  controllers: [BbbController],
  providers: [BbbService],
})
export class BbbModule {}

可以看到,AaaService 依然被注入到 BbbService 里。这就是全局模块。

全局模块只有在必需的时候使用,否则注入的很多 Provider 不知道来源,降低代码的可维护性。

生命周期

Nest 的完整声明周期如图所示。

应用建立的生命周期:

  1. 首先,Nest 会递归初始化模块,依次调用 Controller 和 Provider 内的 onModuleInit() 方法,然后再调用 Module 的 onModuleInit() 方法。
  2. 接着,依次调用 Controller 和 Provider 内的 onApplicationBootstrap() 方法,然后再调用 Module 内的 onApplicationBootstrap() 方法。
  3. 全部初始化完成后,开始监听网络端口,处理请求。之后,Nest 应用就正常运行了。

在这个过程中,onModuleInit()onApplicationBootstrap() 都是可供调用的生命周期方法。

先创建两个 Module:

sh
nest g resource ccc --no-spec
nest g resource ddd --no-spec

分别在 ccc 和 ddd 的 Controller、Service 和 Module 里引入 onModuleInit()onApplicationBootstrap()

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

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

  onApplicationBootstrap() {
    console.log('CccController onApplicationBootstrap')
  }
}
ts
@Injectable()
export class CccService implements OnModuleInit, OnApplicationBootstrap {
  onModuleInit() {
    console.log('CccService onModuleInit')
  }

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

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

在控制台中,能看到生命周期调用顺序的日志信息。

sh
CccController onModuleInit
CccService onModuleInit
CccModule onModuleInit
DddController onModuleInit
DddService onModuleInit
DddModule onModuleInit
CccController onApplicationBootstrap
CccService onApplicationBootstrap
CccModule onApplicationBootstrap
DddController onApplicationBootstrap
DddService onApplicationBootstrap
DddModule onApplicationBootstrap

应用销毁的生命周期:

  1. 首先,Nest 会递归销毁模块,依次调用 Controller 和 Provider 内的 onModuleDestroy() 方法,然后再调用 Module 的 onModuleDestroy() 方法。
  2. 接着,依次调用 Controller 和 Provider 内的 onApplicationShutdown() 方法,然后再调用 Module 内的 onApplicationShutdown() 方法。
  3. 停止监听网络端口并停止进程。

onModuleInit()onModuleDestroy() 除了执行时间不同,实现功能相同。而 onApplicationBootstrap()onApplicationShutdown() 的区别在于,onApplicationShutdown() 可以传入一个 signal 参数。这个参数可以由其它进程传过来,做一些销毁的操作,比如用 k8s 管理容器。

Released under the MIT License.