[Spring] 의존성 주입 (Dependency Injection, DI) 3가지 방법

의존성 주입(Dependency Injection, DI)

Inversion of Control(IoC)이라고도 불리는 의존성 주입(DI)은 클래스 간 의존관계를 관리하고 있는 Bean 중에서 필요한 것을 컨테이너가 자동으로 주입해 주는 것을 말한다. 즉, 어떤 객체가 사용하는 의존 객체를 직접 만들어서 사용하는 게 아니라, 주입받아서 사용하는 방법을 말한다.

 

의존성 주입 방법으로 대표적으로 3가지가 존재하는데 아래에서 알아보자.

 

 

의존관계 주입 방법

생성자 주입 

생성자 주입 방식은 생성자를 통해서 의존 관계를 주입 받는 방법이다.

@RestController
public class PostController {
    private final PostService postService;

    // @Autowired 생성자가 1개인 경우 생략 가능
    public PostController(PostService postService) {
        this.postService = postService;
    }
}

생성자가 1개일 경우 @Autowired 생략해도 자동 주입이 된다.

 

생성자 주입 방식은 3가지 방법 중 가장 권장되는 방식으로 다양한 장점이 존재한다.

 

1. 불변성 확보 

생성자 주입 방식을 사용하면 final 키워드를 사용 할 수 있는데 final을 사용하면 한번 생성할 때(생성자 호출 시점) 정해지면 바뀌지 않는다는 불변성을 확보할 수 있다. 즉 생성자를 호출하는 시점에 딱 1번만 호출되는 것이 보장되기 때문에 이후에 호출되는 일이 없어 불변성을 확보할 수 있다는 장점이 존재한다.

 

아래에서 나올 생성자 주입 방법 중 하나인 setter를 이용하면 final 키워드를 이용할 수 없다.

 

2. 누락 방지 

또 생성자 주입을 사용하면 PostController를 생성한다고 했을때 생성자에 값을 넣지 않을 경우 컴파일 시 오류가 발생해 빠르게 디버깅을 할 수 있다는 장점이 있다.

 

아래와 같이 PostController 생성 시 postService 객체를 주입하지 않으면 컴파일 시 오류가 발생하게 된다.

PostController postController = new PostController();

 

3. 테스트 용이 

생성자로 객체를 주입하다보니 스프링 프레임워크에 의존적이지 않아 순수 자바 코드로 테스트할 수 있다는 장점도 존재한다.

 

수정자 주입 (setter)

수정자 주입 방식은 필드의 값을 변경하는 수정자 메서드(setXxx)를 통해서 의존관계를 주입하는 방법이다.

@RestController
public class PostController {
    private PostService postService;

    @Autowired
    public void setPostController(PostService postService) {
        this.postService = postService;
    }
}

수정자 주입 방식은 final 키워드를 사용하지 못하고 setter메서드에 @Autowired를 붙여서 수정자 메서드를 통해 의존관계를 주입한다.

 

수정자 주입의 단점으로는 setter 메서드를 public으로 열어두는데 이러면 주입받는 객체가 변경이 될 가능성이 존재한다.

그래서 수정자 주입 방식은 선택, 변경 가능성이 있는 의존관계에서 사용한다.

 

또 다른 단점으로 변경될 가능성이 존재하면 불변성을 보장하지 못하고 임의로 객체를 변경할 수 있기 때문에 에러가 발생할 가능성도 높아진다.

 

대부분 의존 관계 주입은 한번 일어나면 종료시점까지 변경할 일이 거의 없어서 수정자 주입 방식은 권장하지 않는 방식이다.

 

필드 주입

필드 주입 방식은 위의 2가지 방법에 비해 단순하게 구현할 수 있다.

아래처럼 필드에 @Autowired를 이용해 바로 주입하는 방법이다.

@RestController
public class PostController {
    @Autowired
    private PostService postService;
    
}

 

하지만 필드 주입 방식은 DI를 지원하는 프레임워크가 없으면 사용할 수 없어 프레임워크에 의존적이라는 단점이 존재한다. 그리고 외부에서 변경이 불가하기 때문에 테스트하기가 힘들다는 단점도 존재하기 때문에 사용을 지양하고 있다.

 

 

결론

의존 관계를 주입하는 방법은 생성자 주입 방식을 사용하는게 좋다.

위에서 알아보았듯이 생성자 주입 방식은 프레임워크에 의존적이지 않아 순수한 자바 코드로 구현이 가능하고, final 키워드를 사용해 불변성을 보장받을 수 있기 때문에 생성자 주입 방식을 사용하는 게 좋다.