[DI] 생성자 주입 사용

ttaho·2023년 11월 27일

Spring

목록 보기
13/13

스프링의 DI(Dependency Injection, 의존성 주입) 중 생성자 주입을 프로젝트를 진행하며 지금껏 사용해왔다.
@RequiredArgsConstructor와 final 키워드를 사용해서 생성자 주입을 기계처럼 사용해왔는데 왜 생성자 주입을 사용해야 하는지 알아보고자 한다.

다양한 의존성 주입 방법

  1. 필드 주입

필드 주입은 @Autowired 어노테이션을 이용해 필드에 바로 의존 관계를 주입하는 방식이다.
해당 방식은 외부에서 접근이 불가능하다는 단점이 있다.

  1. 수정자 주입(Setter 주입)

수정자 주입은 필드 값을 변경하는 Setter를 통해서 의존 관계를 주입하는 방식이다.
주입받는 객체가 변경될 가능성이 있는 경우에 사용한다.
하지만 실제로 변경이 필요한 경우는 매우매우매우 드물다!!
또한 @Autowired로 주입할 대상이 없는 경우에는 오류가 발생한다. 주입할 대상이 없어도 동작하려면 @Autowired(required = false)를 통해 설정할 수 있다.

  1. 생성자 주입

생성자 주입은 생성자의 호출 시점에 1회 호출 되는 것이 보장된다. 그래서 주입받은 객체가 변하지 않거나, 반드시 객체의 주입이 필요한 경우에 강제하기 위해 사용할 수 있다.
또한, 스프링 프레임워크는 생성자가 1개만 있을 경우에 @Autowired를 생략해도 의존관계를 주입하는 것을 지원한다.

그럼 여러가지의 DI 방법 중 생성자 주입을 사용해야 하는 이유는 무엇일까?

생성자 주입을 사용해야 하는 이유

  1. 객체의 불변성 확보

실제 개발 시, 의존 관계의 변경이 필요한 경우는 극히 드물다.
수정자 주입을 사용하게 되면 불필요한 수정의 가능성을 열어두어 유지보수성을 떨어뜨린다. 그러므로 생성자 주입을 사용해서 변경의 가능성을 배제하고 불변성을 보장하는 것이 좋다.

  1. 순환 참조 에러방지

두 서비스 객체가 서로를 참조하는 경우에 애플리케이션을 실행하고, AService, BService 중 아무 곳에서나 hello 메서드를 호출하면 StackOverFlow 에러가 난다.
애플리케이션 실행시점에는 알 수 없고, hello 메서드가 실행될 때 에러가 발생하는 것이므로 hello 메서드가 호출되지 않으면 이 부분을 개발자는 잡을 수가 없다.
이러한 순환 호출 에러를 생성자 주입을 통해 애플리케이션 실행 단계 에서 잡을 수 있다.

  1. 테스트 코드 작성의 편리함

test 코드는 순수 자바 코드로 단위 테스트를 작성하는 것이다.
하지만 필드 주입을 하게되면 UserRepository와 MemberService는 스프링 프레임워크의 DI에 의존하는 것이기 때문에 테스트 코드에서는 UserRepository와 MemberService를 사용할 수 없다.
이를 해결하기 위해 생성자 주입을 하게되면 변경 가능성을 열어두는 것이기 때문에 적절하지 않다.
반면에 생성자 주입을 사용하게 되면 컴파일 시점에 객체를 주입받는 것이기 때문에 객체가 누락된 경우 컴파일 시점에 오류를 발견할 수 있다.

  1. final 키워드 작성 및 Lombok과의 결합
    생성자 주입을 사용하면 필드 객체에 final 키워드를 사용할 수 있으며, 컴파일 시점에 누락된 의존성을 확인할 수 있다. 또한 Lombok의 @RequiredArgsConstructor를 통해 final 변수를 위한 생성자를 자동으로 만들어준다.

결론

여러모로 생성자 주입이 좋기때문에 생성자 주입을 사용하는 버릇을 들이자!

참고

  1. https://mangkyu.tistory.com/125
  2. [Spring] 생성자 주입을 사용해야 하는 이유
profile
SW Engineer

0개의 댓글