在开始本文的讨论之前,让我们先做一道多选题:
下面对于 @Injectable
的描述,哪些是正确的?
A @Injectable 装饰器应该添加到每个服务中。
B @Injectable 装饰器应该添加到任何使用依赖注入 (DI) 的服务中。
C 如果您不使用“providedIn”选项,则不需要添加 @Injectable 装饰器。
D @Injectable 装饰器与“providedIn”选项一起,意味着不应将服务添加到模块的提供者数组中。
答案是 B 和 D.
Angular 带有自己的 DI 框架,并用于 Angular 应用程序的设计以增强其模块化和效率。 @Injectable() 是任何 Angular 服务定义的重要组成部分。 有些人可能选择错误答案的原因是他们错误地判断了@Injectable 装饰器和Angular 中的DI 之间的关系,不了解这个装饰器的真正作用。
Adding @Injectable Is Not Registering the Service
对于用于 DI 的控制反转 (IOC) 容器,有两个成对的知识点需要掌握。 首先是令牌。 要向 IOC 容器注册某些服务,需要一个令牌。 令牌是注册任何服务的唯一标识符。 第二个知识点是 provider.
提供者帮助 DI 容器创建特定依赖项的实例。
在 Angular 中,使用令牌注册服务并将其传递给提供者可以通过两种不同的方式完成。
首先,可以使用特定的 @NgModule 注册服务。 该过程是通过将服务传递给提供者数组 providers
来进行注册。在下面这个例子里,使用的令牌是 typescript 类型 MyService。 这里的提供者是 useClass。 这个提供者策略,通知 Angular 框架,可以通过 new 关键字来启动某个依赖项的实例。
@NgModule({
...
providers: [
// long hand syntax
{provide: MyService, useClass: MyService},
// short hand syntax
MyService
],
})
第二种方式是使用 @Injectable
:
@Injectable({
providedIn: 'root'
})
export class MyService {
constructor() { }
}
这里要注意区分的一点是,@Injectable 装饰器与向容器注册服务无关。 那么@Injectable 装饰器的目的是什么?
事实上,MyService 可以有一些依赖项是标准的。 例如,您可以使用 HttpClient。
import { HttpClient } from '@angular/common/http';
@Injectable()
export class MyService {
constructor(private httpClient: HttpClient) { }
}
让我们尝试了解当您需要获取 MyService 实例时会发生什么。 当 Angular 需要创建服务时,它应该传递一个 HttpClient 的实例。 那么它怎么能做到呢?
首先,Angular 应该知道提到了哪个依赖项。 还记得您使用令牌来注册依赖项吗? 出于同样的原因,您可以向 Angular 请求该依赖项的一个实例。 因此,Angular 将调查构造函数并查看是否为令牌 HttpClient 请求了服务。 如果使用该令牌注册了服务,Angular 可以使用该令牌启动 MyService 并提供它创建的实例。
下面是编译后的 JavaScript 代码:
var MyService = /** @class */ (function () {
function MyService(httpClient) {
this.httpClient = httpClient;
}
MyService = __decorate([
Object(_angular_core__WEBPACK_IMPORTED_MODULE_0__["Injectable"])(),
__metadata(
"design:paramtypes",
[_angular_common_http__WEBPACK_IMPORTED_MODULE_1__["HttpClient"]]
)
], MyService);
return MyService;
}());