NestJS - Provider总结

641 阅读3分钟

在NestJS中,Provider是依赖注入系统的核心概念之一。Provider可以是一个类、值、工厂函数或其他任意的对象,它们通过依赖注入系统提供给需要它们的组件(如控制器、服务等)

Provider 是Injectable**装饰的class,**service是简单的Providers。@Injectable()装饰器附加了元数据,声明该类是由Nest [**IoC**](<https://en.wikipedia.org/wiki/Inversion_of_control>)容器管理的类。

Injectable装饰源码:

截屏2023-12-29 00.39.23.png

依赖注入

  1. 基于构造函数的注入

⚠️ 这种写法 constructor(private catsService: CatsService) {} ,其实等价于。这个简写允许我们在同一位置声明并立即初始化catsService成员。

export class CatsController {
	private catsService: CatsService
  constructor(catsService: CatsService) {
			this.catsService = catsService
	}
}

⚠️这里只是声明了依赖,CatsController 依赖了 CatsService 类。而不是实例,实例化是IoC容器来做的。

  1. 基于属性的注入
@Injectable()
export class HttpService<T> {
  @Inject('HTTP_OPTIONS')
  private readonly httpClient: T;
}

Provider的类型

1 类作为Provider

最常见的Provider类型是类。NestJS会自动实例化这些类并将它们注入到需要它们的地方。

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

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

2 值作为Provider

有时你可能需要提供一个简单的值而不是类实例。在这种情况下,你可以使用useValue

const myValueProvider = {
  provide: 'MY_VALUE',
  useValue: 'This is a value',
};

3 工厂函数作为Provider

工厂函数允许你在Provider实例化时执行一些逻辑。你可以使用useFactory来定义工厂函数。

const myFactoryProvider = {
  provide: 'MY_FACTORY',
  useFactory: () => {
    return new Date().toISOString();
  },
};

4 已存在的Provider

有时你可能希望重用已存在的Provider。你可以使用useExisting来实现这一点。

const myExistingProvider = {
  provide: 'MY_EXISTING',
  useExisting: MyService,
};

在Module中注册Provider

1 注册类Provider

import { Module } from '@nestjs/common';
import { MyService } from './my.service';

@Module({
  providers: [MyService],
  exports: [MyService],
})
export class MyModule {}

2 注册值Provider

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

const myValueProvider = {
  provide: 'MY_VALUE',
  useValue: 'This is a value',
};

@Module({
  providers: [myValueProvider],
  exports: [myValueProvider],
})
export class MyModule {}

3 注册工厂Provider

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

const myFactoryProvider = {
  provide: 'MY_FACTORY',
  useFactory: () => {
    return new Date().toISOString();
  },
};

@Module({
  providers: [myFactoryProvider],
  exports: [myFactoryProvider],
})
export class MyModule {}

注入Provider

1 注入类Provider

import { Controller, Get } from '@nestjs/common';
import { MyService } from './my.service';

@Controller()
export class MyController {
  constructor(private readonly myService: MyService) {}

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

2 注入值Provider

import { Controller, Get, Inject } from '@nestjs/common';

@Controller()
export class MyController {
  constructor(@Inject('MY_VALUE') private readonly myValue: string) {}

  @Get()
  getValue(): string {
    return this.myValue;
  }
}

3 注入工厂Provider

import { Controller, Get, Inject } from '@nestjs/common';

@Controller()
export class MyController {
  constructor(@Inject('MY_FACTORY') private readonly myFactoryValue: string) {}

  @Get()
  getFactoryValue(): string {
    return this.myFactoryValue;
  }
}

Provider的作用域

NestJS中的Provider默认是单例的,这意味着在整个应用程序生命周期中只有一个实例。如果需要每次请求都创建一个新实例,可以将Provider的作用域设置为REQUEST

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

@Injectable({ scope: Scope.REQUEST })
export class MyService {
  getHello(): string {
    return 'Hello World!';
  }
}

5. 自定义Provider令牌

有时你可能希望使用自定义的字符串或符号作为Provider的令牌,以避免命名冲突。

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

const MY_CUSTOM_TOKEN = Symbol('MY_CUSTOM_TOKEN');

const myCustomProvider = {
  provide: MY_CUSTOM_TOKEN,
  useValue: 'This is a custom token value',
};

@Module({
  providers: [myCustomProvider],
  exports: [myCustomProvider],
})
export class MyModule {}

总结

Provider是NestJS依赖注入系统的核心部分,它们可以是类、值、工厂函数或其他对象。通过合理地使用Provider,可以极大地提升代码的可维护性和可测试性。希望这对你理解NestJS中的Provider有所帮助。如果你有任何问题或需要进一步的解释,请告诉我!