2개의 injector 계층
- ModuleInjector 계층
- @NgModule() 이나 @Injectable()를 사용하여 ModuleInjector를 구성함.
- ElementInjector 계층
ModuleInjector
2가지 구성 방법이 있음.
- @Injectable() 에서 providedIn을 사용하고 @NgModule()에 참조
- @NgModule()의 providers 배열에 추가
- ModuleInjector는 NgModule.providers 및 NgModule.imports 속성으로 구성됨.
- NgModule.imports를 재귀적으로 따라가 도달할 수 있는 모든 providers 배열을 flatten 시킴.
- lazy loading하는 NgModules가 있을 때 Child ModuleInjector들이 생김.
Platform injector
- root ModuleInjector 위에 PlatformModule로 구성된 ModuleInjector와 NullInjector() 가 더 있음.
- platformBrowserDynamic() 은 PlatformModule에 의해 구성된 injector 생성함.
- 다음 부모 injector는 NullInjector이고 tree에 top임.
- service을 찾다가 NullInjector를 만나면 null을 return 함.
ElementInjector
- 각 component(and directive)는 dom element를 위한 암묵적으로 ElementInjector를 만든다.
- ElementInjector에는 provider, viewProvider, 자기 자신(component or directive) 등이 포함되어 있다.
- component에서 services를 provide했을때, ElementInjector를 통해 해당 컴포넌트에서 그 service가 사용 가능하다.
- 해당 component가 destroy 되면 service도 destroy된다.
의존성을 찾는 규칙
컴포넌트나 디렉티브에서 provide된 토큰을 찾을 때, angular는 2가지 기준으로 찾기 시작한다.
- ElementInjector 계층 구조에서 먼저 찾고
- ModuleInjector 계층 구조에서 찾는다
순서
- component가 의존성 요청한다.
- angular는 그 component의 ElementInjector에서 의존성을 찾는다.
- 만약 그 component의 injector에 provider가 없다면 부모 component의 ElementInjector에 요청한다.
- 상위 ElementInjector가 부족할 때까지 계속 올라간다.
- 못찾으면 시작된 component로 돌아가서 ModuleInjector 계층 구조를 탐색한다.
- 또 못찾으면 에러를 발생시킨다.
만약 중복으로 provider에 등록했다면, angular는 처음에 찾은 걸 사용하고 다른 provider에 있는건 보지 않는다.
Resoltion modifiers
Angular의 찾는 행위는 modifier에 의해 수정될 수 있다.
- @Optional - 없어도 에러 내지 않음.
- @Self - 해당 컴포넌트의 ElementInjector만 찾아봄.
- @SkipSelf - 부모의 ElementInjector부터 찾기 시작하게 함.(본인 생략)
- @Host - HostComponent(의존성을 요청한 컴포넌트)까지만 찾도록 함.
- 정확히 해당 component가 속해있는 뷰까지만 찾음.
Provider vs viewProvider
@Component에서 provider와 viewProvider property를 사용할 수 있다.
- provider: component 메타데이터에 삽입됨.
- child component도 똑같이 provide된 토큰을 공유해 사용할 수 있다.
- viewProvider: view에서 사용가능하도록 한다.
- ng-content로 들어온 component에서는 provide되지 않는다.
- ng-content는 component의 view 안에 속하지 않기 때문
- view 안에 명시된 component는 똑같이 공유 가능하다.
- component class도 view이기 때문에 사용 가능하다.
- ng-content로 들어온 component에서는 provide되지 않는다.
참조