在NestJS中,Provider是依赖注入系统的核心概念之一。Provider可以是一个类、值、工厂函数或其他任意的对象,它们通过依赖注入系统提供给需要它们的组件(如控制器、服务等)
Provider 是Injectable**装饰的class,**service是简单的Providers。@Injectable()装饰器附加了元数据,声明该类是由Nest [**IoC**](<https://en.wikipedia.org/wiki/Inversion_of_control>)容器管理的类。
Injectable装饰源码:
依赖注入
- 基于构造函数的注入
⚠️ 这种写法 constructor(private catsService: CatsService) {} ,其实等价于。这个简写允许我们在同一位置声明并立即初始化catsService成员。
export class CatsController {
private catsService: CatsService
constructor(catsService: CatsService) {
this.catsService = catsService
}
}
⚠️这里只是声明了依赖,CatsController 依赖了 CatsService 类。而不是实例,实例化是IoC容器来做的。
- 基于属性的注入
@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有所帮助。如果你有任何问题或需要进一步的解释,请告诉我!