providers: [
{
provide: CheckoutDeliveryService,
useClass: MockCheckoutDeliveryService,
},
A dependency provider configures an injector with a DI token, which that injector uses to provide the concrete, runtime version of a dependency value. The injector relies on the provider configuration to create instances of the dependencies that it injects into components, directives, pipes, and other services.
provider使用一个DI token配置injector,后者使用该token创建一个具体的能用于运行时的实例,该实例可以注入到Component,指令,管道和其他服务里。
下列两种写法等价:
- providers: [Logger]
- [{ provide: Logger, useClass: Logger }]
provide字段:holds the token that serves as the key for both locating a dependency value and configuring the injector.
存储了一个token,作为定位一个依赖值和配置injector的key.
第二个值是provider definition object,provider的定义对象,告诉injector如何创建被依赖的值。除了useClass之外,还有useExisting, useValue, useFactory等等。
The second property is a provider definition object, which tells the injector how to create the dependency value. The provider-definition key can be useClass, as in the example. It can also be useExisting, useValue, or useFactory. Each of these keys provides a different type of dependency, as discussed below.
不同的class可以provide同一个服务。
下列代码的含义是,如果有代码需要一个Logger,那么返回一个BetterLogger实例。
[{ provide: Logger, useClass: BetterLogger }]
看下面这段代码:
@Injectable()
export class EvenBetterLogger extends Logger {
constructor(private userService: UserService) { super(); }
log(message: string) {
const name = this.userService.user.name;
super.log(`Message to ${name}: ${message}`);
}
}
正确的injector配置方式:
[ UserService,
{ provide: Logger, useClass: EvenBetterLogger }]
Value providers
有时我们也可以让injector返回一个事先准备好的对象,即value provider的配置。
比如下面这个对象:
// An object in the shape of the logger service
function silentLoggerFn() {}
export const SilentLogger = {
logs: ['Silent logger says "Shhhhh!". Provided via "useValue"'],
log: silentLoggerFn
};
使用useValue返回这个对象:
[{ provide: Logger, useValue: SilentLogger }]
如何只注入一个简单的字符串呢?
export const HERO_DI_CONFIG: AppConfig = {
apiEndpoint: 'api.heroes.com',
title: 'Dependency Injection'
};
The HERO_DI_CONFIG constant conforms to the AppConfig interface. Unfortunately, you cannot use a TypeScript interface as a token. In TypeScript, an interface is a design-time artifact, and doesn’t have a runtime representation (token) that the DI framework can use.
TypeScript里的接口是一个design time的概念,而DI框架需要一个运行时载体即DI token,因此接口并不能直接参与到Angular的DI中去。
解决方案1
在NgModule里提供和注入configuration对象:
providers: [
UserService,
{ provide: APP_CONFIG, useValue: HERO_DI_CONFIG }
],
解决方案2
使用InjectionToken object.
import { InjectionToken } from '@angular/core';
export const APP_CONFIG = new InjectionToken<AppConfig>('app.config');
现在就可以注册依赖了:
providers: [{ provide: APP_CONFIG, useValue: HERO_DI_CONFIG }]
在任何构造函数里可以使用这个依赖:
constructor(@Inject(APP_CONFIG) config: AppConfig) {
this.title = config.title;
}