跳到主要内容

依赖注入

nestjs 实现了一个 IOC 容器,存储着可以依赖注入的类(使用了 @Injectable )和被注入的类(@Controller),IOC 容器可以屏蔽一些类的实例化操作。

使用 @injectable 修饰的类,可以被注入到其他类中,同时也能被注入其他的依赖对象。

使用 provider(提供者)来实现 DI​

一般 Module providers 的 provide 是一个 token 时,在依赖注入时,需要使用 @Inject 来注入依赖

这几种情况是不需要使用 @Inject 的

  1. provide 配置的是类,而不是 token
  2. Module providers 直接存储需要注入的类
  3. Module 直接引入其他模块的 Module(被引入 Module exports 中的依赖会被引入到当前 Module 中)

使用 useClass​

提供给当前模块的是一个类,这个类最终由 IOC 容器来实例化为一个对象,使用 Inject 修饰器就可以将这个对象修饰到目标类的实例对象上,通过 this 可以直接使用了

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

@Module({
imports: [],
controllers: [AppController],
providers: [
// 是下面写法的一种语法糖吧
AppService,
{
// provide: 'user_service',
provide: UserService,
// class 有 IOC 容器来实例化
useClass: UserService,
},
],
})
export class AppModule {}

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

@Controller()
export class AppController {
constructor(
private readonly appService: AppService,
// provide 是类就不需要使用 @Inject 修饰器了
// @Inject('user_service')
private readonly userService: UserService,
) {}

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

使用 useValue​

这种方式可以提供一个静态的值,这个值可以是对象,也可以是一个基础类型的数据

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

@Module({
imports: [],
controllers: [AppController],
providers: [
AppService,
{
provide: 'name',
useValue: 'xiaoliu',
},
],
})
export class AppModule {}

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

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

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

使用 useFactory​

useFactory 可以生成一个动态的值,同时支持异步操作

useFactory 也可以参数注入,注入的参数必须是在当前模块中的 provider

执行时机:初始化 Module 时执行取值,只执行一次,所以取得值在整个代码运行周期中是不变的

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

@Module({
imports: [],
controllers: [AppController],
providers: [
AppService,
{
provide: 'name',
useValue: 'asfd',
},
{
provide: 'user',
// 支持异步
async useFactory(name: string, userService: UserService) {
await new Promise((resolve) => setTimeout(resolve, 1000));
return {
...userService.getUser(),
name,
};
},
inject: ['name', 'user_service'],
},
{
provide: 'user_service',
// class 有 IOC 容器来实例化
useClass: UserService,
},
],
})
export class AppModule {}

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

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

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

使用 useExisting​

使用已有的 provider,provide token 是一个别名

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

@Module({
imports: [],
controllers: [AppController],
providers: [
AppService,
{
provide: 'name',
useValue: 'xiaoliu',
},
{
provide: 'name1',
useExisting: 'name',
},
],
})
export class AppModule {}

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

@Controller()
export class AppController {
constructor(
private readonly appService: AppService,
@Inject('name1')
private readonly name1: string,
) {}

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

全局模块​

Module​

我们代码大部分都是以 Module 为单位来引入其他模块的

使用 @Module 表示声明了一个模块对象,当前模块的依赖和向外导出的依赖都是在这定义的相当于一个功能模块出入口,他有这几个属性

  • imports 引入其他模块 exports 导出的内容
  • providers 为当前模块提供依赖,比如当前模块的 Service
  • exports 向外导出的依赖,一般导出的是 providers 中的内容
  • controllers 当前模块需要的 Controller
import { Module } from '@nestjs/common';
import { LoginService } from './login.service';
import { LoginController } from './login.controller';
import { UserModule } from 'src/user/user.module';

@Module({
imports: [UserModule], // 引入其他模块 exports 出的内容
controllers: [LoginController], // 模块的控制器
providers: [LoginService], // 模块运行需要的依赖入口
exports: [LoginService], // 模块导出的依赖出口
})
export class LoginModule {}

Global​

如果某个模块在在很多地方被导入了,我们可以在 Module 使用 Global 装饰器将当前模块定义到全局位置,其他模块使用时就不需要再 imports 中导入了

import { Module } from '@nestjs/common';
import { LoginService } from './login.service';
import { LoginController } from './login.controller';
import { UserModule } from 'src/user/user.module';

@Global()
@Module({
imports: [UserModule], // 引入其他模块 exports 出的内容
controllers: [LoginController], // 模块的控制器
providers: [LoginService], // 模块运行需要的依赖入口
exports: [LoginService], // 模块导出的依赖出口
})
export class LoginModule {}