IoC

IoC(Inversion of Control) 控制反转,是 Java Spring 中非常重要的思想和核心。
在面向对象的软件开发过程中,随着应用规模越来越庞大,对象之间的依赖关系也越来越复杂,经常会出现对象之间的多重依赖关系。

  1. import A from './A'
  2. import B from './B'
  3. export class App {
  4. constructor() {
  5. this.a = new A()
  6. this.b = new B()
  7. }
  8. }

在上面的示例代码中,App 依赖A、B,并在构造器中进行实例化。这就形成了耦合,当存在大量依赖或需求频繁变动时,应用会变得越来越难以维护。
为了解决对象间耦合度过高的问题,IoC出现了。
IoC是控制翻转,那么到底是哪些控制被反转了呢?答案是 获取依赖对象的过程被翻转了。

  1. import Container from 'Container'
  2. import A from './A'
  3. import B from './B'
  4. const container = new Container()
  5. container.bind(A)
  6. container.bind(B)
  7. export class App {
  8. constructor() {
  9. this.a = container.get('A')
  10. this.b = container.get('B')
  11. }
  12. }

如上面的代码所示,获取依赖对象的过程,由内部实例化变为由 IoC 容器来实例化。

DI

DI (Dependency Injection) 依赖注入,即应用运行期间,由 IoC 容器动态地注入依赖。nestjs 的依赖注入,深受 Angular 的影响。nestjs 中的 IoC 容器,就是 nestjs 运行时系统。下面对这个流程做一下简单说明。

首先定义一个提供者,或者说服务:

  1. import { Injectable } from '@nestjs/common'
  2. @Injectable()
  3. export class UserService {
  4. findAll() {
  5. return []
  6. }
  7. }

然后将提供者作为依赖,注入控制器类中使用:

  1. import { Controller, Get } from '@nestjs/common'
  2. import { UserService } from './user.service'
  3. @Controller('user')
  4. export class UserController {
  5. // 声明所需依赖
  6. constructor(private readonly userService: UserService) {}
  7. @Get()
  8. async findAll() {
  9. return this.userService.findAll()
  10. }
  11. }

最后,在 IoC 容器中注册提供者:

  1. import { Module } from '@nestjs/common';
  2. import { UserController } from './user/user.controller';
  3. import { UserService } from './user/user.service';
  4. @Module({
  5. controllers: [UserController],
  6. providers: [UserService],
  7. })
  8. export class AppModule {}

通过上述步骤,IoC 容器就会为 UserController 自动注入实例。这里有三个关键步骤:

  1. 在 service 中用 @Injectable 声明一个可以由 IoC 容器管理的类。
  2. 在 controller 的构造函数中声明依赖。
  3. 在 app.module.ts 中,注册 UserService 类。

更多详细说明,请参考 自定义提供者