의존관계 주입(DI)

2 minute read

의존관계 주입(DI)

💎 의존관계란
  • 두 개의 클래스 또는 모듈이 의존관계에 있다고 말할 때는 항상 방향성을 부여해줘야 한다.

    • 즉, 누가 누구에게 의존하는 관계에 있다는 식

    • 아래 그림은 A가 B에 의존하고 있음을 나타낸다.

image-20220616134137841

  • 의존한다는 건 의존대상, 위에서는 B가 변하면 그것에 A에 영향을 미친다는 뜻이다.
    • B의 기능이 추가되거나 변경되거나, 형식이 바뀌거나 하면 그 영향이 A로 전달된다는 것이다.

💎 의존관계 주입

  • 의존 관계 주입은 구체적인 의존 오브젝트와 그것을 사용할 주체, 보통 클라이언트라고 부르는 오브젝트를 런타임 시에 연결해주는 작업을 말하며, 다음과 같이 세 가지 조건을 충족한다.

    • 클래스 모델이나 코드에는 런타임 시점의 의존관계가 드러나지 않는다. 그러기 위해서는 인터페이스에만 의존하고 있어야 한다. (결합도가 낮아진다)

    • 런타임 시점의 의존관계는 컨테이너나 팩토리 같은 제 3의 존재가 결정한다.

    • 의존관계는 사용할 오브젝트에 대한 레퍼런스를 외부에서 제공(주입) 해줌으로써 만들어진다.

  • 의존관계 주입의 핵심은 설계 시점에는 알지 못했던 두 오브젝트의 관계를 맺도록 도와주는 제 3의 존재가 있다는 것이다.
    • 스프링의 애플리케이션 컨텍스트, 빈팩토리, IoC 컨테이너 등이 모두 외부에서 오브젝트 사이의 런타임 관계를 맺어주는 책임을 지닌 제 3의 존재라고 볼 수 있다.
  • 의존관계 주입을 위한 코드 예시
public class UserDao {
    private ConnectionMaker connectionMaker;
    
    //connectionMaker를 구현한 어떤 구현체가 올지 모른다.
    public UserDao(ConnectionMaker connectionMaker) { 
        this.connectionMaker = connectionMaker;
    }
}
  • DI 컨테이너는 UserDao를 만드는 시점에서 성성자의 파라미터로 이미 만들어진 DConnectionMaker의 오브젝트 레퍼런스를 전달한다.

    • 이렇게 생성자 파라미터를 통해 전달받은 런타임 의존관계를 갖는 오브젝트는 인스턴스 변수에 저장해둔다.
  • 이렇게 DI 컨테이너에 의해 런타임 시에 의존 오브젝트를 사용할 수 있도록 그 레퍼런스를 전달받는 과정이 마치 메소드(생성자)를 통해 DI 컨테이너가 UserDao에게 주입해주는 것과 같다고 해서 이를 의존관계 주입이라고 한다.

image-20220616140541630


💎 의존관계 검색과 주입
  • 스프링이 제공하는 IoC 방법에는 의존관계 주입만 있는 것이 아니다.
    • 코드에서는 구체적인 클래스에 의존하지 않고, 런타임 시에 의존관계를 결정한다는 점에서 의존관계 주입과 비슷하지만, 의존관계를 맺는 방법이 외부로부터의 주입이 아니라 스스로 검색을 이용하기 때문에 의존관계 검색(dependency lookup)이라고 불리는 것도 있다.
  • 의존관계 검색은 자신이 필요로 하는 의존 오브젝트를 능동적으로 찾는다.

    • 자신이 어떤 클래스의 오브젝트를 이용할지 결정하지는 않는다.

    • 의존 관계 검색은 런타임 시 의존관계를 맺을 오브젝트를 결정하는 것과 오브젝트의 생성 작업은 외부 컨테이너에게 IoC로 맡기지만, 이를 가져올 때는 메소드나 생성자를 통한 주입 대신 스스로 컨테이너에게 요청하는 방법을 사용한다.

  • 의존관계 검색 이용 예시 코드
public UserDao() {
    AnnotationConfigApplicationContext context = 
        new AnnotationConfigApplicationContext(DaoFactory.class);
    this.container = context.getBean("connectionMaker", ConnectionMaker.class);
}

💎 의존관계 검색 vs 의존관계 주입
  • 의존 관계 주입이 의존관계 검색보다는 훨씬 단순하고 깔끔하다.

  • 하지만 의존관계 검색 방식을 사용해야 할 때가 있다.

    • ex) 스태틱 메소드 main()에서는 DI를 이용해 오브젝트를 주입 받을 방법이 없다.

    • 서버 또한 main()과 같은 기동 메소드는 없지만 사용자의 요청을 받을 때마다 main() 메소드와 비슷한 역할을 하는 서블릿에서 스프링 컨테이너에 담긴 오브젝트를 사용하려면 한 번은 의존관계 검색 방식을 사용해 오브젝트를 가져와야 한다.

      • 하지만 서블릿은 스프링이 미리 만들어서 제공하기 때문에 직접 구현할 필요는 없다.
  • 의존관계 검색과 의존관계 주입을 적용할 때 중요한 차이점

    • 의존관계 검색 방식에서는 검색하는 오브젝트는 자신이 스프링의 빈일 필요가 없다는 점이다.

    • 의존관계 주입에서는 DI가 적용되려면 반드시 컨테이너가 관리하는 빈 오브젝트여야 한다.


💎 의존관계 주입의 장점
  • 코드에는 런타임 클래스에 대한 의존관계가 나타나지 않는다.

  • 인터페이스를 통해 결합도가 낮은 코드를 만들므로, 다른 책임을 가진 사용 의존관계에 있는 대상이 바뀌거나 변경되더라도 자신은 영향을 받지 않으며, 변경을 통한 다양한 확장 방법에는 자유롭다

Comments