수정자 DI, 생성자 DI

2022. 11. 2. 17:49Spring 기초

스프링 DI 방법 2가지

Dependency Injection(의존관계 주입)

강한 결합

  • 객체 내부에서 다른 객체를 생성하면 강한 결합도를 갖게된다.
  • A 클래스 내부에서 B라는 객체를 직접 생성할 경우, B 객체를 C로 변경해야 한다면 A 클래스 내부의 코드를 직접 수정해야한다.
  • 런타임 이전에 의존관계가 이미 형성된다.

느슨한 결합

  • 객체를 주입받는다는 것은 외부에서 생성된 객체를 인터페이스를 통해 넘겨받는 것을 의미한다.
  • 이는 결합도를 낮추고 런타임 시에 의존관계가 결정된다.

스프링에서는 의존관계 주입을 통해 객체 간 느슨한 결합을 유지할 수 있는데, 대표적으로 의존관계를 주입할 수 있는 Setter 주입과 생성자 주입에 대해 알아보자.

1. Setter 주입

IDE의 자동생성 기능으로 setter 메소드를 생성한다.

public class UserDao {
    private ConnectionMaker connectionMaker;

    public void setConnectionMaker(ConnectionMaker connectionMaker) {
        this.connectionMaker = connectionMaker;
    }
}

UserDao는 수정자 메소드 DI 방식이 가능하므로 Configuration 설정정보에서 DI를 사용해보자.

@Bean
    public ConnectionMaker connectionMaker() {
        reeturn new DConnectionMaker();
    }
    
    @Bean
    public UserDao userDao() {
        UserDao userDao = new UserDao();
        
        //수정자 주입
        userDao.setConnectionMaker(connectionMaker());
        return userDao;
    }

수정자 주입을 통해 UserDao는 ConnectionMaker와 낮은 결합도를 갖게 되었다.

하지만 Setter 주입의 문제점은,
1. ConnectionMaker의 구현체를 주입해주지 않아도 UserDao객체는 생성이 가능하다는 것이다.
UserDao 객체를 생성하고 내부에서 ConnectionMaker의 메소드를 호출한다면
NullPointerException이 발생한다.
⇒ 필요한 객체가 주입되지 않아도 얼마든지 객체를 생성할 수 있다는 문제가 있다.

2. 수정자 주입을 위해서는 setter를 public으로 열어놓게 되는데, 다른 곳에서 변경될 가능성이 존재한다.

곧바로 살펴볼 생성자 주입에서는 이런 문제들을 해결했다.

2. 생성자 주입

userDao에 setter를 제거하고, 생성자를 이용해 주입받는다.

public class UserDao {
    private ConnectionMaker connectionMaker;

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

사용하는 쪽에서는

public class Main{
    public static void main(String[] args) {
        UserDao userDao = new UserDao(new DConnectionMaker());
    }
}

생성자를 통해 필요한 객체를 주입하게된다.

이 경우 장점이 네가지가 있는데,

  1. null을 주입하는 것이 아니라면 NPE는 발생하지 않는다.
  2. 의존관계 주입을 깜빡하고 하지 않는 경우, UserDao 객체를 생성할 수 없다.
    ⇒ 컴파일 타임에 오류를 잡아낼 수 있다.
  3. final 키워드를 사용할 수 있다.
    ⇒ final로 선언된 변수는 반드시 선언과 함께 초기화가 되어야 한다. 따라서 나중에 주입이 이루어지는 setter 주입은 final을 이용할 수 없다.
  4. 단위 테스트가 쉽다.
    ⇒ 여기서 안다뤘지만 필드 주입 방식은 IoC가 빈 생성 후 자동으로 주입해주는 방식이라 단위테스트에서 해당 객체를 생성한 뒤 주입하기 까다롭다. 하지만 생성자 주입으로 설계하는 경우 객체를 생성할 때 필요한 구현체를 넘겨주면 되므로 단위 테스트가 편리하다.

 


참고

https://www.baeldung.com/constructor-injection-in-spring

 

Constructor Dependency Injection in Spring | Baeldung

Quick and practical intro to Constructor based injection with Spring.

www.baeldung.com

토비의 스프링 vol1