Home
프로필

DI 그리고 IoC 컨테이너

image

💡 의존성 주입

Dependency Injection(DI)
  • 클래스 안에서 다른 클래스를 만드는 기본적인 방법은 new 키워드를 사용하여 새로운 인스턴스를 생성하는 것이다.

    class A {
    const b = new B();
    }

  • 반면 의존성 주입이라 함은 생성자를 통해 외부에서 인스턴스를 주입받는 방식을 의미한다.

    class A {
    constructor(private readonly b: B) {}
    }

여기서 클래스 B 없이는 A의 생성이 성립되지 않는다. 이런 관계를 A는 B에 의존한다고 말한다. 그리고 이 연결이 성공적이면 B는 A에 주입된다고도 할 수 있다.

  • Dependencies는 클래스가 동작하기 위해 필요한 서비스나 객체를 의미한다.
  • DI란 다른 인스턴스를 클래스 안에서 생성하는 대신, 바깥에서 주입받는 디자인 패턴을 의미한다.
  • DI를 이용하면 객체를 생성하고 사용할 때 관심사를 분리할 수 있다. 이는 코드의 가독성과 재사용성을 향상시킨다.

💡 IoC 컨테이너

그런데 저렇게 선언만 한다고 해서 뭐가 짠, 저절로 이루어지는 것은 아니다. 요구되는 인스턴스를 만들고 넣어줘야 하지 않나? 원래라면 그런데, NestJS에서는 그 과정이 생략된다.
왜냐면 NestJS가 주입 가능한 클래스의 인스턴스를 자동으로 생성해주기 때문이다. 이런 게 프레임워크의 힘이겠지 아마? 그리고 프레임워크에서 그 작업을 도맡아 하고 있는 부분이 IoC 컨테이너다. 개발자는 그에게 단지 어떤 클래스가 DI로 활용될 객체인지 알려주면 된다. @Injectable() 데코레이터가 그 역할을 한다. 멋진 신세계.

  • IoC 컨테이너의 도움으로 객체의 라이프 사이클에 신경 쓰지 않아도 된다.
  • 인스턴스의 생성과 폐기를 신경 쓰지 않고 비즈니스 로직에만 집중할 수 있다.
  • 별도의 스코프를 지정하지 않으면 Singleton 인스턴스로 생성되어 불필요한 중복, 낭비를 막는다.

The @Injectable() decorator attaches metadata, which declares a class can be managed by the Nest IoC container. 공식문서

💡 제어의 역전

Inversion of Control(IoC)
  • 라이브러리와 프레임워크를 구분할 수 있는 기준이다.
  • 코드의 흐름을 제어하는 주체가 나에서 프레임워크로 바뀌는 것.
  • DI는 IoC를 실현하기 위한, 즉 프레임워크에서 제어권을 가지기 위해 구현된 여러 디자인 패턴 중 하나이다.
  • 프레임워크는 자신의 틀에서 요구되는 객체에만 관심이 있으며, 그 형식만 충족한다면 구체적인 내용(구현)은 상관없다.
  • NestJS에서 이는 데코레이터에 들어 있는 metadata로 구별된다.
  • 어플리케이션의 제어 책임이 프로그래머에서 프레임워크로 넘어가고, 개발자는 비즈니스 로직에 집중할 수 있게 된다.
이미지
조잡한 예제

가령 위 사진의 B는 서비스 / A는 컨트롤러에 대입될 수 있다. 컨트롤러에서 서비스의 주입이 요구되는 순간, IoC 컨테이너에서 이 클래스가 DI임을 식별하고 인스턴스를 생성 ➝ 주입한다. NestJS는 cli로 모듈을 만들 때 이 패턴을 기본으로 쥐어준다. 하위 서비스를 직접 만들어 쓰더라도 @Injectable() 데코레이터를 붙이기만 하면 모듈에 등록하여 쓸 수 있다.

  • @Injectable() 데코레이터는 해당 클래스를 DI로 활용하겠다고 프레임워크에 보내는 일종의 딱지다.
  • 이 클래스가 어딘가에 주입되는 상황에 NestJS의 IoC 컨테이너가 해당 클래스의 인스턴스를 자동으로 생성해 넣어준다.
  • 이렇게 의존성으로 들어가는 클래스를 더 일반적으로 부르는 말이 Provider다. NestJS에서는 서비스, 리포지토리, 미들웨어 등이 모두 Provider다.
  • 어딘가로 주입될 수 있다는 말은 다른 클래스에 연결되고 또 그 안에서 사용될 수 있다는 의미다.

Providers are a fundamental concept in Nest. Many of the basic Nest classes may be treated as a provider – services, repositories, factories, helpers, and so on. The main idea of a provider is that it can be injected as a dependency; this means objects can create various relationships with each other, and the function of "wiring up" these objects can largely be delegated to the Nest runtime system. 공식문서

  • 특정 모듈에서 사용된 DI는 아래와 같이 providers에 등록하고 사용 가능하다. 빠트려도 에러로 알려주긴 하지만 경험상 자주 빠트리니 주의하도록 한다.!
    posts.module.ts

    @Module({
    controllers: [PostsController],
    providers: [PostsService, SubService, 주입되는클래스], // 등록
    })
    export class PostsModule {}



참고링크

Comment ?

▾ Comment

🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧 🚧