理解 Angular 的依赖注入
概览
依赖注入是一种设计模式,它的主要作用是让类与其依赖相互独立。它能够解决的现实问题是,当一个类 classA 需要依赖另一些类 classB、classC 时,不再需要 classA 中去实例化 classB、classC,即一个类不需要知道它所依赖的其他服务的具体实现,而是直接去使用其依赖。另外还能够便于编写单测、减少冗余代码、使应用便于扩展。
注入的依赖可以是任何类或值。
Angular 框架中有三种依赖注入的类型:
- Constructor Injection:injector 将依赖(服务)在类构建时注入其中
- Setter Injection:injector 将依赖注入到 setter 属性方法中
- Interface Injection: 依赖本身自带 injector,可以将依赖注入任何传入其中的使用者。接受该依赖的使用者必须通过 interface 暴露一个 setter 方法。
Injector
Injector 是能够存储指令来实现 service 的数据结构,能够将 service 实例化,是 DI 系统里的一个中介角色。
Module、directive 和 component 类都拥有自己的 metadata 装饰器,其中 providers: [] 可以声明使用哪些将哪些 service 注册到类中。每一个 injector 都会陪伴某一个类,也就是说整棵应用树会对应一棵 injector tree。
在 service 里,通过 Injectable({providedIn: string}) 表示 injector 在哪里创建 service。providedIn 属性指明该 service 应该用哪个 injector 去注册。这样可以很容易实现 tree-shaking 来减少不必要的 service 实例化。该属性默认是 ‘root’,也就是说该服务在应用内任何地方均可实例化使用。
注册好的 service 是单例的——只有一个 injector 可以去初始化该 service。
在 @Directive、@Component 和 @Module 元数据中则是通过 providers 来表示。
Module 和 Component都拥有自己的 injector,注册在其中的 service 是跟随其生命周期存在。
实例化 References
在 Angular 中,reference 也是 service 的一种。但是我们从来不会手动将 ElementRef、Renderer2 这些服务写在任何 providers 中,这是因为 angular 会自动将很多 service 注册在 root provider 中。
Injection Token
Angular 的 DI 系统使用 tokens 来标识一个 Provider。有三种 tokens:Type Token、String Token、Injection Token。
1 | providers :[{ provide: ProductService, useClass: ProductService }] |
其中 provide 属性值就是一个 DI Token 标识,userClass 属性值就是一个 Provider,服务的具体实现。
Type Token
最常见的是当依赖是一个 service 时,provide 属性值就是这个服务类的 type。
String Token
当注入的依赖没有具体的类型时,可以直接使用 string token 进行标识:
1 | providers: [{ provide: 'USE_FAKE', useValue: true }] |
但是 string token 有一个很严重的问题,就是在一个应用中,可能不同的开发者会使用相同的 string token 去注入不同的依赖,甚至可能会和第三方包中的 token 发生重复和冲突。
所以需要另外一种: Injection Token
Injection Token
Injection Token 能够创建一个 token,它可以是任意类型
1 | import { InjectionToken } from '@angular/core'; |
可以看到,Injection Token 类似与 String Token,但是能够保证全局唯一。
参考文章:
https://angular.io/guide/dependency-injection
https://angular.io/guide/dependency-injection-overview
https://angular.io/guide/architecture-services
https://www.simplilearn.com/tutorials/angular-tutorial/angular-dependency-injection
https://www.codesolutionstuff.com/dependency-injection-in-angular-with-example
https://www.tektutorialshub.com/angular/injection-token-in-angular