티스토리 뷰

반응형

1. 의존성 주입(Dependency Injection)의 개념과 필요성


[ 의존성 주입(Dependency Injection) 이란? ]

Spring 프레임워크는 3가지 핵심 프로그래밍 모델을 지원하고 있는데, 그 중 하나가 의존성 주입(Dependency Injection, DI) 이다. DI란 외부에서 두 객체 간의 관계를 결정해주는 디자인 패턴으로, 인터페이스를 사이에 둬서 클래스 레벨에서는 의존관계가 고정되지 않도록 하고 런타임 시에 관계를 다이나믹하게 주입하여 유연성을 확보하고 결합도를 낮출 수 있게 해준다.

의존성이란 한 객체가 다른 객체를 사용할 때 의존성이 있다고 한다.

예를 들어 다음과 같이 Store 객체가 Pencil 객체를 사용하고 있는 경우에 우리는 Store객체가 Pencil 객체에 의존성이 있다고 표현한다.

public class Store {

    private Pencil pencil;

}

 

그리고 두 객체 간의 관계(의존성)를 맺어주는 것을 의존성 주입이라고 하며 생성자 주입, 필드 주입, 수정자 주입 등 다양한 주입 방법이 있다. Spring 4부터는 생성자 주입을 강력히 권장하고 있는데, 이와 관련된 내용은 이 글에서 참고하도록 하자.

 

[ 의존성 주입(Dependency Injection)이 필요한 이유 ]

예를 들어 연필이라는 상품과 1개의 연필을 판매하는 Store 클래스가 있다고 하자.

public class Pencil {

}
public class Store {

    private Pencil pencil;

    public Store() {
        this.pencil = new Pencil();
    }

}

위와 같은 예시 클래스는 크게 다음과 같은 문제점을 가지고 있다.

  • 두 클래스가 강하게 결합되어 있음
  • 객체들 간의 관계가 아니라 클래스 간의 관계가 맺어지고 있음

1. 두 클래스가 강하게 결합되어 있음

위와 같은 Store 클래스는 현재 Pencil 클래스와 강하게 결합되어 있다는 문제점을 가지고 있다. 두 클래스가 강하게 결합되어 있어서 만약 Store에서 Pencil이 아닌 Food와 같은 다른 상품을 판매하고자 한다면 Store 클래스의 생성자에 변경이 필요하다. 즉, 유연성이 떨어진다. 각각의 다른 상품들을 판매하기 위해 생성자만 다르고 나머지는 중복되는 Store 클래스들이 파생되는 것은 좋지 못하다. 이에 대한 해결책으로 상속을 떠올릴 수 있지만, 상속은 제약이 많고 확장성이 떨어지므로 피하는 것이 좋다.

 

2. 객체들 간의 관계가 아니라 클래스 간의 관계가 맺어지고 있음

또한 위의 Store와 Pencil는 객체들 간의 관계가 아니라 클래스들 간의 관계가 맺어져 있다는 문제가 있다. 올바른 객체지향적 설계라면 객체들 간에 관계가 맺어져야 하지만 현재는 Store 클래스와 Pencil 클래스가 관계를 맺고 있다. 객체들 간에 관계가 맺어졌다면 다른 객체의 구체 클래스(Pencil인지 Food 인지 등)를 전혀 알지 못하더라도, (해당 클래스가 인터페이스를 구현했다면) 인터페이스의 타입(Product)으로 사용할 수 있다.

 

결국 위와 같은 문제점이 발생하는 근본적인 이유는 Store에서 불필요하게 어떤 제품을 판매할 지에 대한 관심이 분리되지 않았기 때문이다. Spring에서는 DI를 적용하여 이러한 문제를 해결하고자 하였다.

 

[ 의존성 주입(Dependency Injection)을 통한 문제 해결 ]

위와 같은 문제를 해결하기 위해서는 우선 다형성이 필요하다. Pencil, Food 등 여러 가지 제품을 하나로 표현하기 위해서는 Product 라는 Interface가 필요하다. 그리고 Pencil에서 Product 인터페이스를 우선 구현해주도록 하자.

public interface Product {

}
public class Pencil implements Product {

}

 

이제 우리는 Store와 Pencil이 강하게 결합되어 있는 부분을 제거해주어야 한다. 이를 제거하기 위해서는 다음과 같이 외부에서 상품을 주입(Injection)받아야 한다.

public class Store {

    private Product product;

    public Store(Product product) {
        this.product = product;
    }

}

 

여기서 Spring이 DI 컨테이너를 필요로 하는 이유를 알 수 있는데, 우선 Store에서 Product 객체를 주입하기 위해서는 애플리케이션 실행 시점에 필요한 객체(빈)를 생성해야 하며, 의존성이 있는 두 객체를 연결하기 위해 한 객체를 다른 객체로 주입시켜야 하기 때문이다.

예를 들어 다음과 같이 Pencil 이라는 객체를 만들고, 그 객체를 Store로 주입시켜주는 역할을 위해 DI 컨테이너가 필요하게 된 것이다.

public class BeanFactory {

    public void store() {
        // Bean의 생성
        Product pencil = new Pencil();
    
        // 의존성 주입
        Store store = new Store(pencil);
    }
    
}

 

 그리고 이러한 개념은 제어의 역전(Inversion of Control, IoC)라고 불리기도 한다. 어떠한 객체를 사용할지에 대한 책임이 BeanFactory와 같은 클래스에게 넘어갔고, 자신은 수동적으로 주입받는 객체를 사용하기 때문이다. (실제 Spring에서는 BeanFactory를 확장한 Application Context를 사용한다.)

 

 

2. 의존성 주입(Dependency Injection, DI) 정리


[ 의존성 주입(Dependency Injection) 정리 ]

한 객체가 어떤 객체(구체 클래스)에 의존할 것인지는 별도의 관심사이다. Spring에서는 DI 컨테이너를 통해 서로 강하게 결합되어 있는 두 클래스를 분리하고, 두 객체 간의 관계를 결정해 줌으로써 결합도를 낮추고 유연성을 확보하고자 하였다. 의존성 주입으로 애플리케이션 실행 시점에 객체를 생성하고 관계를 결정해 줌으로써 다른 구체 클래스에 의존하는 코드를 제거하며 서로 다른 두 객체의 결합을 약하게 만들어 주었다. 또한 이러한 방법은 상속보다 훨씬 유연하다. 단, 여기서 주의해야 하는 것은 다른 빈을 주입받으려면 자기 자신이 반드시 컨테이너의 빈이여야 한다는 것이다.

 

  • 두 객체 간의 관계라는 관심사의 분리
  • 두 객체 간의 결합도를 낮춤
  • 객체의 유연성을 높임
  • 테스트 작성을 용이하게 함

 

하지만 의존 관계를 주입할 객체를 계속해서 생성하고 소멸한다면, 아무리 GC가 성능이 좋아졌다고 하더라도 부담이 된다. 그래서 Spring에서는 Bean들을 기본적으로 싱글톤(Singleton)으로 관리하는데, 우리는 이에 대해 자세히 알 필요가 있다.

 

 

 

 

 

 

관련 포스팅

  1. 의존성 주입(Dependency Injection, DI)이란? 및 Spring이 의존성 주입을 지원하는 이유 - (1/2)
  2. 다양한 의존성 주입 방법과 생성자 주입을 사용해야 하는 이유 - (2/2)
반응형
댓글
댓글쓰기 폼
  • 코딩의신 안녕하세요. IT 기술 면접을 보기 전 내용 정리를 위하여 IT 기술 블로그를 찾다가 해당 블로그를 발견하였습니다.
    내용이 너무 알차서, 블로그에 포스팅된 모든 글을 읽고있습니다.

    제가 봤던 그 어떤 블로그들보다도 내용을 쉽게 이해할 수 있게 정리를 잘 해주신 것 같습니다. 너무너무 감사합니다
    DI, IOC에 대해서도 개념이 명확하게 잡혀있지 않아 항상 헷갈렸었는데
    이 글을 보니 명확히 정리가 되네요

    두꺼운 기술책을 보며 정리하는 것에 부담이 됐었는데, 이렇게 간략하게 잘 명시해주셔서 너무 감사합니다

    나중에 책도 한권 집필해주셨으면 좋겠네요 ㅎㅎ
    2021.05.19 21:32
  • 망나니개발자 벌써 기술 블로그를 시작한지 4년차가 되었네요ㅎㅎ 그 동안 제가 블로그에 포스팅을 할 때
    - 올바른 정보만을 전달할 것
    - 누가봐도 이해하기 쉽게 정리할 것
    위의 2가지 만큼은 반드시 지키려고 노력하는데, 그런 부분들이 잘 전달되는 것 같아서 상당히 뿌듯하네요:)
    항상 글 올리는게 주춤할 뻔 하다가도 이렇게 응원해주시는 좋은 댓글들 덕분에 꾸준히 포스팅을 하게 되는 것 같습니다. 정말 감사합니다:)
    2021.05.20 00:13 신고
  • mina 이 글을 보니 DI가 뭔 지 느낌이 오네요...! 감사합니다. 2021.06.09 17:23
  • 망나니개발자 DI가 처음 접하면 쉬운 개념은 아닌데, 잘 이해가 되셨다니 뿌듯하네요ㅎㅎ 감사합니다:) 2021.06.24 15:58 신고
  • 뎁뎁 저도 아래 댓글처럼 너무 정리가 잘 되었어요 감사해용 2021.07.15 17:41
  • 망나니개발자 도움이 된 것 같아서 뿌듯하네요:)
    감사합니다ㅎㅎ 자주 들러주세욤!!
    2021.07.15 20:01 신고
  • yooooonms 감사합니다.
    DI가 뭔지는 알고 있었지만 DI를 사용함으로써 얻는 이점
    왜 사용하는지에 대해서는 아리송했는데 이 글 보고 알게 되었습니다.
    2021.07.28 19:54
  • 망나니개발자 도움이 많이 된 것 같아 뿌듯하네요ㅎㅎ 감사합니다:) 2021.07.28 21:06 신고
  • 코딩배우는학생 DI에 대해서 정말 감이 잡히지 않았는데 이 글을 보고나니 DI가 어떤 것인지에 대해서 조금은 감이 잡혔습니다ㅠㅠ
    이렇게 좋은 글을 써주셔서 정말 감사합니다ㅎㅎ
    2021.09.02 17:06
  • 망나니개발자 DI가 처음 접하면 쉬운 개념이 아닐 수 있습니닷ㅎㅎ 그래도 감 잡으셨다니 다행이네욤:) 2021.09.03 00:15 신고
  • 정영준 제가 본 DI 관련 글들 중 최고네요! 공부하는데 정말 많은 도움이 되었습니다 ㅜㅜ 앞으로도 좋은 글 기대할게요!
    괜찮으시다면 출처를 밝히고 인용해도 괜찮을까요?
    2021.10.28 19:12
  • 망나니개발자 도움이 많이 되셨다니 뿌듯하네요ㅎㅎ 넵넵 출처 남기고 인용해주세요! 감사합니다:) 2021.10.28 19:59 신고
반응형
공지사항
Total
1,765,524
Today
405
Yesterday
4,771
TAG more
«   2021/12   »
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  
글 보관함