- 의존성 주입
- 어떤 서비스를 직접 인스턴스화하거나 관리할 필요를 제거하고, 코드의 재사용성, 테스트 용이성, 그리고 간결성을 향상.
- 간단한 예로 controller가 요청을 처리하면 복잡한 비즈니스 로직을 위임받아 처리해주는 역할
- provider가 될 수 있는 것들 → 서비스, 레포지토리, 팩토리 등등
- 주입된 의존성이 선택적인 경우 @optional() 설정 가능
- 환경변수 NEST_DEBUG=true 로 특정 프로바이더가 어떤 모듈에 등록되는지 확인할 수 있다.
import { Injectable, Optional, Inject } from '@nestjs/common';
@Injectable()
export class HttpService<T> {
constructor(@Optional() @Inject('HTTP_OPTIONS') private httpClient: T) {}
}
- scope: 기본적으로 싱글톤이지만 scope 옵션을 통해 변경 가능
NestJs에서 IoC가 구현되는 순서
- 모듈 초기화
- NestFactory.create() 메서드를 호출하여 어플리케이션 인스턴스를 생성하며 시작됨 (IoC컨테이너도 이 시점에 생성)
- Root 모듈부터 시작하여 각 모듈의 imports 배열에 명시된 모듈들을 차례(재귀)로 로드하고 모든 모듈을 로드한다.
- 모듈이 로드되는 동안, IoC컨테이너는 각 모듈 메타데이터를 사용하여 의존성 그래프를 생성하고 그것에 따라 필요한 인스턴스를 생성하고 주입한다.
- 의존성 그래프: 각 클래스가 어떤 의존성을 요구하는지 나타냄
- 모든 provider와 controller를 인스턴스화 한다.
- 이 과정에서 해당 인스턴스가 다른인스턴스에 의존하는 경우, 의존성이 주입된다. 이 과정에서 인스턴스들이 싱글톤으로 관리되고 재사용된다.
- 모든 인스턴스는 IoC컨테이너에 의해 싱글톤(default)로 관리된다.
- IoC 컨테이너는 각 모듈을 초기화하고 관리한다
IoC란?
- 제어의 반전
- 일반적으로 개발자의 코드가 라이브러리나 다른 코드를 호출하여 제어하지만 개발자가 아닌 프레임워크가 제어하게하여 개발자는 비즈니스 로직에만 집중하게 되고 프레임워크가 객체의 생명주기나 의존성등을 관리하게 된다.
DI란?
- 클래스 A와 B가 존재하고 A는 B의 기능을 필요로 할 때 A는 B에 의존하게되고 B는 A의 의존성이라고 한다.
- 이러한 의존성을 A가 직접 생성하거나 불러오는 대신 외부에서 제공받아 사용한다.
nestjs 라이프 사이클
- 요청 - 미들웨어 - 가드 - 인터셉터 - 파이프 - 라우트핸들러 - 인터셉터 - 응답