likes
comments
collection
share

神光《Nest 通关秘籍》学习总结-深入理解Provider如何注入对象

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

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

神光《Nest 通关秘籍》学习总结-深入理解Provider如何注入对象 想购买的可以点击《传送门》。

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

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

本章我们来学习nest中的如何使用provider注入对象。

provider 一般都是用 @Injectable 修饰的 class:

// app.service.ts
import { Injectable } from '@nestjs/common';

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

然后在 Module 的 providers 里声明:

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

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

Provider的完整的写法是这样的:

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

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

通过 provide 指定注入的 token,通过 useClass 指定注入的对象的类,Nest 会自动对它做实例化再注入。

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();
  }
}

除了使用构造器注入,还可以使用属性的方式注入:

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

@Controller()
export class AppController {
  @Inject(AppService)
  private readonly appService: AppService;

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
}

如果provide是一个字符串:

...
@Module({
  imports: [],
  controllers: [AppController],
  providers: [
    {
      provide: 'app_service',
      useClass: AppService,
    },
  ],
})
...

在注入的时候,就需要使用 @Inject 手动指定注入对象的 provide

...
@Controller()
export class AppController {
  @Inject('app_service')
  private readonly appService: AppService;

  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
}
// or
...
@Controller()
export class AppController {
  constructor(@Inject('app_service') private readonly appService: AppService) {}
  @Get()
  getHello(): string {
    return this.appService.getHello();
  }
}

一般我们都是直接使用class的方式去注入,方便简洁。

我们还可以在Provider里面使用useValue注入一个值:

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

@Module({
  imports: [],
  controllers: [AppController],
  providers: [
    {
      provide: 'app_service',
      useClass: AppService,
    },
    {
      provide: 'person',
      useValue: {
        name: 'xiumubai',
        age: 18,
      },
    },
  ],
})
export class AppModule {}

然后在对象里注入它:

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

@Controller()
export class AppController {
  constructor(
    @Inject('app_service') private readonly appService: AppService,
    @Inject('person')
    private readonly person: { name: string; age: number },
  ) {}

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

使用断点调试,可以看到值:

神光《Nest 通关秘籍》学习总结-深入理解Provider如何注入对象

使用useFactory可以动态的来动态创建一个对象:

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

@Module({
  imports: [],
  controllers: [AppController],
  providers: [
    {
      provide: 'app_service',
      useClass: AppService,
    },
    {
      provide: 'person',
      useValue: {
        name: 'xiumubai',
        age: 18,
      },
    },
    {
      provide: 'person2',
      useFactory() {
        return {
          name: '朽木白',
          age: 40,
        };
      },
    },
  ],
})
export class AppModule {}
import { Controller, Get, Inject } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(
    @Inject('app_service') private readonly appService: AppService,
    @Inject('person')
    private readonly person: { name: string; age: number },
    @Inject('person2')
    private readonly person2: { name: string; age: number },
  ) {}

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

神光《Nest 通关秘籍》学习总结-深入理解Provider如何注入对象

还可以使用动态参数注入:

...
{
  provide: 'person3',
  useFactory(person: { name: string }, appService: AppService) {
    return {
      name: person.name,
      desc: appService.getHello(),
    };
  },
  inject: ['person', 'app_service'],
},
...
import { Controller, Get, Inject } from '@nestjs/common';
import { AppService } from './app.service';

@Controller()
export class AppController {
  constructor(
    @Inject('app_service') private readonly appService: AppService,
    @Inject('person')
    private readonly person: { name: string; age: number },
    @Inject('person2')
    private readonly person2: { name: string; age: number },
    @Inject('person3')
    private readonly person3: { name: string; desc: string },
  ) {}

  @Get()
  getHello(): string {
    console.log(this.person);
    console.log(this.person2);
    console.log(this.person3);
    return this.appService.getHello();
  }
}

神光《Nest 通关秘籍》学习总结-深入理解Provider如何注入对象

useFactory还支持异步的使用:

{
  provide: 'person3',
  async useFactory(person: { name: string }, appService: AppService) {
    await new Promise((resolve) => {
      setTimeout(resolve, 3000);
    });
    return {
      name: person.name,
      desc: appService.getHello(),
    };
  },
  inject: ['person', 'app_service'],
},

provider 还可以通过 useExisting 来指定别名,这里就是给 person2 的 token 的 provider 起个新的 token 叫做 person4。

 {
  provide: 'pserson4',
  useExisting: 'person2',
},

总结:

  • provider 是通过 @Injectable 声明,然后在 @Module 的 providers 数组里注册的 class。
  • 默认的 token 就是 class,这样不用使用 @Inject 来指定注入的 token。
  • 但也可以用字符串类型的 token,不过注入的时候要用 @Inject 单独指定。
  • 除了可以用 useClass 指定注入的 class,还可以用 useValue 直接指定注入的对象。
  • 如果想动态生成对象,可以使用 useFactory,它的参数也注入 IOC 容器中的对象,然后动态返回 provider 的对象。
  • 如果想起别名,可以用 usExisting 给已有的 token,指定一个新 token。
  • 灵活运用这些 provider 类型,就可以利用 Nest 的 IOC 容器中注入任何对象。
转载自:https://juejin.cn/post/7242198986261856317
评论
请登录