베어_
TechBear
베어_
전체 방문자
오늘
어제
  • 분류 전체보기 (336)
    • Spring (33)
      • 개념 (13)
      • Security (5)
      • 실습 (1)
      • 토비 스프링 (11)
    • JPA (6)
    • 프로젝트 기록 (24)
    • DB (13)
    • JAVA (18)
    • 알고리즘 (50)
      • 유형정리 (8)
      • Baekjoon (21)
      • LeetCode (18)
    • 디자인패턴 (0)
    • 개발서적 (79)
      • Effective Java (78)
      • 객체지향의 사실과 오해 (1)
    • 독후감 (4)
    • 보안 (2)
    • 운영체제(OS) (53)
      • 공룡책 (53)
    • 컴퓨터 네트워크 (28)
      • 컴퓨터 네트워크 하향식 접근 (23)
    • 자료구조 (1)
    • DevOps (2)
    • 앱 개발 (20)
      • 안드로이드 스튜디오 (20)

블로그 메뉴

    공지사항

    인기 글

    태그

    • 백준
    • Spring
    • leetcode
    • BFS
    • 코드업
    • java
    • 스프링
    • 토비스프링
    • 운영체제
    • 자바
    • 스프링시큐리티
    • 데이터베이스
    • 자바8
    • 알고리즘
    • 스레드
    • 이펙티브자바
    • 함수형인터페이스
    • jpa
    • dfs
    • C++

    최근 댓글

    최근 글

    티스토리

    hELLO · Designed By 정상우.
    베어_

    TechBear

    [토비 스프링] 의존관계 주입(DI)
    Spring/토비 스프링

    [토비 스프링] 의존관계 주입(DI)

    2023. 6. 11. 20:03

    의존관계 주입(DI)

    제어의 역전과 의존관계 주입

    • DaoFactory처럼 객체를 생성하고 관계를 맺어주는 등의 작업을 담당하는 기능을 일반화한 것이 스프링의 IoC 컨테이너이다. 스프링이 제공하는 IoC방식의 핵심은 의존 관계 주입(DI)이다.
    • 의존성 주입이란 오브젝트 레퍼런스를 외부로부터 제공(주입)받고 이를 통해 여타 오브젝트와 다이나믹하게 의존관계가 만들어지는 것을 의미한다.

    의존관계

    두 개의 클래스 또는 모듈이 의존관게에 있다는 할 때는 항상 방향성이 존재한다. 다음에서는 A가 B에 의존하고 있음을 의미한다.

    의존관계 도식도

    A는 B에게 의존하고 있기 때문에 B에서 특정 메소드가 추가 혹은 수정되면 A에게도 영향을 미친다.

    UserDao의 의존관계

    UserDao의 의존관계를 살펴보면 ConnectionMaker라는 인터페이스에 의존하고 있음을 알 수 있다. 하지만 UserDao의 입장에서 DConnectionMaker라는 구현체의 존재를 알 수 없기 때문에 DConnectionMaker의 메소드가 추가, 수정되어도 UserDao에게 영향을 주지 않는다. 이처럼 인터페이스에 대해서만 의존관계를 만들어두면 인터페이스 구현 클래스와의 관계는 느슨해지면서 변화에 영향을 덜 받는 상태가 된다.

    인터페이스를 통한 느슨한 결합

    이처럼 UML 관계에서 나오는 의존관계는 설계 모델의 관점에서 이야기하는 것이다. 의존관계에는 런타임 시에 오브젝트 사이에서 만들어지는 의존관계도 존재한다.

    런타임 시 발생하는 의존관계

    • 인터페이스를 통해 설계 시점에 느슨한 의존관계를 갖는 경우에는 UserDao의 오브젝트가 런타임 시에 사용할 오브젝트가 어떤 클래스로 만든 것인지 미리 알 수가 없다. 의존관계 주입은 이렇게 구체적인 의존 오브젝트와 그것을 사용할 주체, 보통 클라이언트라고 부르는 오브젝트를 런타임 시에 연결해주는 작업을 말한다.
    • 프로그램이 시작되고 UserDao 오브젝트가 만들어지고 나서 런타임 시에 의존관계를 맺는 대상, 즉 실제 사용대상인 오브젝트를 의존 오브젝트라고 말한다.

    UserDao를 통해 알아보는 의존관계 주입

    UserDao를 개선하기 전에는 다음과 같이 DConnectionMaker()라는 구현 클래스를 알고 있었다.

    public UserDao() {
        connectionMaker = new DConnectionMaker();
    }

    이를 UserDao() 생성자를 통해 ConnectionMaker의 구현체를 주입받도록 함으로써, 즉 제 3자(DaoFactory)에게 ConnectionMaker의 구현체를 결정하고, 레퍼런스를 넘겨주도록 함으로써 이를 해결했다.

    public class UserDao {
    
        private ConnectionMaker connectionMaker;
    
        public UserDao(ConnectionMaker connectionMaker) {
            this.connectionMaker = connectionMaker;
        }
    }

    DaoFacotry는 여기서 두 오브젝트 사이의 런타임 의존관계를 설정해주는 의존관계 주입 작업을 주도하는 존재이며, 동시에 IoC방식으로 오브젝트의 생성과 초기화, 제공 등의 작업을 수행하는 컨테이너이다. 이렇게 의존관계 주입을 담당하는 컨테이너를 DI 컨테이너라고 한다. DI 컨테이너는 UserDao를 만드는 시점에서 생성자의 파라미터로 이미 만들어진 DConnectionMaker의 오브젝트를 전달한다.

    의존관계 검색과 주입

    의존관계 검색

    • 스프링이 제공하는 IoC방법에는 의존관계 주입뿐만이 아니라 의존관계 검색이라는 기능도 제공한다. 의존관계를 맺는 방법이 외부로부터의 주입이 아니라 스스로 검색하는 방식이다. 이를 예시를 통해 알아보자.

    다음과 같이 UserDao의 생성자 리스트를 만들었다고 가정하자.

    public UserDao() {
        DaoFactory daoFactory = new DaoFactory();
        this.connectionMaker = daoFactory.connectionMaker();
    }

    이렇게 해도 UserDao는 어떤 ConnectionMaker를 사용하는지 알지 못한다. 따라서 IoC 개념을 잘 따르고 있으며, 그 혜택을 받는다고 할 수 있다. 하지만 그 적용 방법이 스프링이 제공하는 방식과 다르다. 즉, 외부로부터의 주입이 아니라 스스로 IoC 컨테이너인 DaoFactory에게 요청하는 것이다. 스프링에서는 미리 정해놓은 이름을 전달해서 그 이름에 해당하는 오브젝트를 찾아온다.

    다음은 의존관계 검색 방식으로 ConnectionMaker 오브젝트를 가져오는 코드이다. 위에서와 달리 connectionMaker는 getBean() 메소드를 통한 검색 방법을 통해 ConnectionMaker 오브젝트를 가져온다.

    public UserDao() {
        AnnotationConfigApplicationContext context =
            new AnnotationConfigApplicationContext(DaoFactory.class);
        this.connectionMaker = context.getBean("connectionMaker", ConnectionMaker.class);
    }

    의존관계 검색과 주입 방식중에 어떤 것이 더 나을까? 코드를 보면 의존관계 검색에서는 오브젝트 팩토리 클래스나, 스프링 API가 나타난다. 따라서 대개는 의존관계 주입 방식을 사용하는 편이 낫다. 그런데 의존관게 검색 방식을 사용해야만 할 때가 있다. (스태틱 메소드인 main(), 서버에서 main()과 같은 기동 메소드는 없지만, 사용자의 요청을 받을 때 마다 main() 메소드와 비슷한 역할을 하는 서블릿)

    의존관계 검색과 주입의 차이점

    의존관계 검색 방식에서는 검색하는 오브젝트는 자신이 스프링의 빈일 필요가 없다. 반면에 의존관계 주입에서는 UserDao와 ConnectionMaker 사이에 DI가 적용되려면 UserDao도 반드시 컨테이너가 만드는 빈 오브젝트여야 한다. (UserDao에 ConnectionMaker 오브젝트를 주입해주려면 UserDao에 대한 생성과 초기화 권한을 갖고 있어야 하고, 그러려면 UserDao는 IoC 방식으로 컨테이너에서 생성되는 오브젝트, 즉 빈이여야 한다.)

    저작자표시 비영리 변경금지 (새창열림)
      'Spring/토비 스프링' 카테고리의 다른 글
      • [토비 스프링] CH2-2. 스프링과 JUnit
      • [토비 스프링] CH2-1. 테스트
      • [토비 스프링] CH1-3. 싱글톤 레지스트리와 오브젝트 스코프
      • [토비 스프링] CH1-2. 제어의 역전
      베어_
      베어_
      Today I learned | 문제를 해결하는 개발자

      티스토리툴바