likes
comments
collection
share

神光《Nest 通关秘籍》学习总结-理解IOC机制

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

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

神光《Nest 通关秘籍》学习总结-理解IOC机制 想购买的可以点击《传送门》。

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

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

本章我们来学习nest中的IOC机制。

在Nest项目中,我们可以看到很多这样奇奇怪怪的写法:

这样的:

神光《Nest 通关秘籍》学习总结-理解IOC机制

这样的:

神光《Nest 通关秘籍》学习总结-理解IOC机制

还有这样的:

神光《Nest 通关秘籍》学习总结-理解IOC机制

乍一看,这些都是啥东西啊,好像跟我们平时写的前端不太一样啊。它的controllerservicemodule它们都是class对象,都没有new呢,它们怎么调用的呢?它为什么可以这么写呢?

要想搞懂它们,首先你得知道什么是IOC(Inverse Of Control)。

老规矩,先搞个项目:

nest new nest-app-ioc

先介绍一下在没有IOC之前我们创建对象都是这样的:

const config = new Config({ username: 'xxx', password: 'xxx'});

const dataSource = new DataSource(config);

const repository = new Repository(dataSource);

const service = new Service(repository);

const controller = new Controller(service);

要经过一系列的初始化之后才可以使用 Controller 对象。在应用初始化的时候,需要理清依赖的先后关系,创建一大堆对象组合起来,还要保证不要多次 new,是不是很麻烦?这个问题是每一个后端系统都有的痛点问题。

而IOC就是解决这个痛点的方式。那么它是如何解决的呢?

之前我们手动创建和组装对象不是很麻烦么,我能不能在 class 上声明依赖了啥,然后让工具去分析我声明的依赖关系,根据先后顺序自动把对象创建好了,然后组装起来呢?

我们把IOC想像成一个容器,程序初始化的时候会扫描 class 上声明的依赖关系,然后把这些 class 都给 new 一个实例放到容器里。创建对象的时候,还会把它们依赖的对象注入进去。这样不就完成了自动的对象创建和组装么?这种依赖注入的方式叫做 Dependency Injection,简称 DI。本来是手动 new 依赖对象,然后组装起来,现在是声明依赖了啥,等待被注入。

从主动创建依赖到被动等待依赖注入,这就是 Inverse Of Control,反转控制。

在 class 上声明依赖的方式,大家都选择了装饰器的方式(在 java 里这种语法叫做注解)。

下面我们在实际项目中来看看Nest是这么利用IOC的。

前面我们已经创建好了项目。我们看看代码里它是怎么创建对象的:

app.service.ts中:

import { Injectable } from '@nestjs/common';

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

它有一个 AppService 声明了 @Injectable,代表这个 class 可注入,那么 nest 就会把它的对象放到 IOC 容器里。

紧接着,在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();
  }
}

AppController 声明了 @Controller,代表这个 class 可以被注入,nest 也会把它放到 IOC 容器里。

然后在 AppModule 里引入:

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

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

通过 @Module 声明模块,其中 controllers 是控制器,只能被注入。

providers 里可以被注入,也可以注入别的对象,比如这里的 AppService。

然后在入口模块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);
}
bootstrap();

当 nest启动以后就会从 AppModule 开始解析 class 上通过装饰器声明的依赖信息,自动创建和组装对象,也就是自动帮我们做了new的操作。这样以来,我们就可以在controller中直接调用service中的方法了:

神光《Nest 通关秘籍》学习总结-理解IOC机制

同样的,当再来一个别的模块,比如我们创建一个person模块:

nest g resource person --no-spec

我们在PersonModule中exports一个PersonService

import { Module } from '@nestjs/common';
import { PersonService } from './person.service';
import { PersonController } from './person.controller';

@Module({
  controllers: [PersonController],
  providers: [PersonService],
  exports: [PersonService],
})
export class PersonModule {}

然后在AppModuleimportsPersonModule,

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

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

这样一来我们是不是就可以在AppController中使用PersonModule中的PersonService了,因为它已经被注入了IOC容器了:

import { Controller, Get } from '@nestjs/common';
import { AppService } from './app.service';
import { PersonService } from './person/person.service';
@Controller()
export class AppController {
  constructor(
    private readonly appService: AppService,
    private readonly personService: PersonService,
  ) {}

  @Get()
  getHello(): string {
    console.log(this.personService.findAll());
    return this.appService.getHello();
  }
}

可以看到打印日志:

神光《Nest 通关秘籍》学习总结-理解IOC机制

已经成功的调用了PersonService中的findAll方法了。

这就是模块如何引用模块的方式,我们通过OC依赖注入的这种思想,来维护整个项目模块之间的依赖,我们不需要关系它们是如何注入的,我们只是需要在使用它的地方注入就行了,这就是 Nest 的 IOC 机制。你懂了没有?

最后总结一句:

Nest 里通过 @Controller 声明可以被注入的 controller,通过 @Injectable 声明可以被注入也可以注入别的对象的 provider,然后在 @Module 声明的模块里引入。

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