Introduction
Angular里面的Injector是分层级的,主要有以下两个层级:
- EnvironmentInjector
- ElementInjector
EnvironmentInjector
EnvironmentInjector层级是通过以下两种方式创建的:
@Injectable({ providedIn: 'xxx' })
- xxx 可以是root
,platform
.providers
array inApplicationConfig
ElementInjector
ElementInjector是创建在每个Dom元素上的,初始时是空的,当我们在@Directive
或者@Component
中声明了一个provider时,Angular会在ElementInjector中创建一个实例。
ModuleInjector
在基于模块的应用中,每个模块都有一个ModuleInjector,ModuleInjector可以通过如下方式配置:
Injectable({ providedIn: 'xxx' })
- xxx 可以是platform
,root
.providers
array in@NgModule
PlatformInjector
在root
Injector之上,还有两个Injector,分别是:
- 一个额外的EnvironmentInjector - 即
PlatformInjector
. - NullInjector.
注意:PlatformInjector
是为了多个Angular app服务的,对于基于Nx的超大型Angular项目,一个项目中可能包含多个app(比如使用了Module Federation)而root injector是针对app的,如果要跨app共享服务,那么就要使用PlatformInjector
了。
看一下Angular的启动代码(位于src/main.ts
文件中):
1 | bootstrapApplication(AppComponent, appConfig); |
当执行上述代码时,Angular首先创建一个Platform Injector(也是Environment Injector),然后创建一个Platform Injector的child Injector,也就是root Environment Injector。而在Platform Injector之上,还有一个额外的NullInjector。
所以NullInjector
是整个Injector链条的顶端,我们在查找一个依赖时,会顺着这个链条向上查找,如果到了NullInjector
还没找到,则会抛出异常。相信很多同学都遇到过下面的错误吧,仔细看报错信息第一行,就是NullInjector
!
ElementInjector
Angular会为每个Dom元素隐式创建一个ElementInjector,当我们在@Directive
或者@Component
中声明了一个provider
或者viewProvider
时,Angular会在ElementInjector中创建一个实例。
依赖解决规则(查找规则)
当Angular为一个Component或者Directive查找依赖时,遵循如下规则:
- 先查找Component或者Directive自身的ElementInjector,如果找到则返回。否则进入下一步。
- 查找Component或者Directive的Parents的ElementInjector,再查找Parents的Parents的ElementInjector,一直如此直到找到,否则进入下一步。
- 查找Component或Directive的EnvironmentInjector层级,此过程同ElementInjector,一直向上查找,如果找到则返回,否则报错。
此处应该加入一张图。
依赖解决修饰符
上面介绍的依赖解决规则,可以用以下修饰符来改变,你可以从@angular/core
中引入这些修饰符:
@Optional
- 如果找不到依赖,不会报错,而是返回null
。@SkipSelf
- 跳过当前ElementInjector,向上查找。@Self
- 只在当前ElementInjector中查找依赖,不会向上查找。@Host
- 只在当前Component及其Host Element的Injector中查找依赖。
这些修饰符可以分为三类:
- What to do if Angular doesn’t find what you’re looking for, this is
@Optional()
- Where to start looking, that is
@SkipSelf
. - Where to stop looking,
@Host
and@Self
.
使用修饰符
这些修饰符都是在constructor
中注入依赖时使用的,比如:
1 | constructor(private myService: MyService) {} () |
关于这些修饰符的详细使用规则,请看这篇。