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 계층 구조에서 찾는다

순서

  1. component가 의존성 요청한다.
  2. angular는 그 component의 ElementInjector에서 의존성을 찾는다.
  3. 만약 그 component의 injector에 provider가 없다면 부모 component의 ElementInjector에 요청한다.
  4. 상위 ElementInjector가 부족할 때까지 계속 올라간다.
  5. 못찾으면 시작된 component로 돌아가서 ModuleInjector 계층 구조를 탐색한다.
  6. 또 못찾으면 에러를 발생시킨다.

만약 중복으로 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이기 때문에 사용 가능하다.

참조

https://angular.io/guide/hierarchical-dependency-injection