从上图能看出,所有注入的示例都通过factory方法返回,只是factory方法的实现有所差异。
As we can see in the picture above all of providers can be presented similar useFactory. When it’s the time to get an instance of provider angular just calls factory function.
一些例子:
{provide: Class1, useClass: Class1}
1
等价于:
Class1
1
而:
{provide: Class1, useClass: Class3}
1
you can configure, that when a constructor requests Class1 Angular DI creates an instance of Class3 and passes it to the constructor.
当构造函数的参数需要传入Class1时,Angular DI传入一个Class3的框实例到构造函数里。
而下面这个例子:
{provide: Class2, useExisting: Class2}
1
doesn’t result in an instance being created, but you can see this rather than an alias. If a constructor requests Class2, Angular DI looks for another provider for key Class2 and injects the instance from this Class2 provider. You can see useExisting like a reference to another provider or an alias.
当构造函数需要Class2时,Angular DI从另一个key为Class2的provider里查找,取出对应的实例进行注入。
Injectable and Provider are 2 different things. The injectable is a class DI can create an instance of, or a provided value that might be passed to a constructor. A provider is an entry in a registry of providers that DI maintains and that allows to lookup up providers by key (key is the type of a constructor parameter, a string or an InjectToken). The provider also holds information about how to “create” the injectable value/instance. DI looks up a provider, the provider provides the value, and DI passes the value (instance of an injectable or a value provided as-is) to a constructor.
Injectable和Provider是两个不同的概念。Injectable是一个class,Angular DI可以基于该class创建实例,或者DI可以提供一个值,能够传递到constructor里。DI内部维护了一个provider注册表,该注册表支持根据key查询provider.
Key is the type of a constructor parameter, a string or an InjectToken)
key是构造函数的参数,一个字符串或者InjectToken. Provider有足够的knowledge知道如何去创建一个value或者实例。
DI询问provider,provider提供值,DI将值传递到构造函数里。
If you register MyClass as provider, this is the short form of { provide: MyClass, useClass: MyValue } where provide: MyClass is the key a provider can be found with, and useClass: MyValue is a strategy passed to the provider that informs the provider what value it should provide for this key.
provide: MyClass是provider的key,Angular DI注册表里根据这个key找到provider.
useClass: MyValue, 一个传递给provider的strategy,告诉provider对于指定的key,应该提供何种value.
useClass: MyValue相当于"use new MyClass(…)"
useExisting: Foo
DI需要去查找key为Foo的provider,然后注入Foo provider提供的value.
看一些具体的例子。
UseExisting
在注入ServiceOldS时,使用ServiceNewS这个provider提供的值。
因此,运行时,old和newService两个实例指向的都是newService实例,都是ServiceNewS这个provider注入的实例:
The provide property holds the token that serves as the key for both locating a dependency value and configuring the injector.
别名提供者:useExisting
useExisting 提供了一个键,让你可以把一个令牌映射成另一个令牌。实际上,第一个令牌就是第二个令牌所关联的服务的别名,这样就创建了访问同一个服务对象的两种途径。
{ provide: MinimalLogger, useExisting: LoggerService }
1
useExisting 的作用
你可以使用别名接口来窄化 API。下面的例子中使用别名就是为了这个目的。
想象 LoggerService 有个很大的 API 接口,远超过现有的三个方法和一个属性。你可能希望把 API 接口收窄到只有两个你确实需要的成员。在这个例子中,MinimalLogger类-接口,就这个 API 成功缩小到了只有两个成员:
// Class used as a "narrowing" interface that exposes a minimal logger
// Other members of the actual implementation are invisible
export abstract class MinimalLogger {
abstract logs: string[];
abstract logInfo: (msg: string) => void;
}
1
2
3
4
5
6
消费代码:
@Component({
selector: 'app-hero-of-the-month',
templateUrl: './hero-of-the-month.component.html',
// TODO: move this aliasing, `useExisting` provider to the AppModule
providers: [{ provide: MinimalLogger, useExisting: LoggerService }]
})
export class HeroOfTheMonthComponent {
logs: string[] = [];
constructor(logger: MinimalLogger) {
logger.logInfo('starting up');
}
}
1=
HeroOfTheMonthComponent 构造函数的 logger 参数是一个 MinimalLogger 类型,在支持 TypeScript 感知的编辑器里,只能看到它的两个成员 logs 和 logInfo: