Spring Basic 13 - Dependency Injection 02
다양한 의존관계 주입방법
생성자 주입
- 생성자 주입은 생성자의 호출 시점에 1회 호출이 되는 것을 보장한다. 그렇기 때문에 주입받은 객체가 변하지 않거나, 반드시 객체의 주입이 필요한 경우에
강제하기 위해사용할 수 있다. - Spring은 생성자 주입을 적극 추천하고 있기 때문에 생성자가 한개만 있을 경우엔 @Autowired를 생략해도 주입이 가능하도록 편의성을 제공한다. 따라서 위에 두 코드는 같은 기능을 하는 코드라고 볼 수 있다.
수정자 주입
@Autowired로 주입할 대상이 없으면 오류가 발생한다. 주입할 대상이 없어도 동작하도록 만드려면 @Autowired(required = false)를 통해 설정은 가능하다. 스프링 초기에는 수정자 주입이 자주 사용되었다고 한다. 당시에는 setXXX, getXXX들의 프로퍼티 기반으로 요구하는 자바의 기본 스펙 때문이었다고 한다. 하지만 시간이 지나면서 점차 수정자 주입이 아닌 생성자 주입으로 발전하게 되었다.
필드 주입
필드 주입을 사용하게 되면 코드가 간결해지고 보기는 좋아진다. 하지만 필드주입을 이용하게 되면, 추천하지 않는다는 문구가 뜬다. 이유는 외부에서 접근이 불가능하다는 단점이 존재하게 되는데, 테스트 코드의 중요성이 부각됨에 따라서 외부에서 사용할 수 없다는 이유로 지양하는 방식이 되었다.
생성자 주입이 가장 권장되는 방식이다.
- 이유는 객체의 불변성을 확보하고, 테스트 코드의 작성이 용이하며, final 키워드 작성 및 Lombok과의 결합 순환 참조 에러 방지가 이유가 될 수 있다.
- 실제로 개발을 하다 보면 의존 관계의 변경이 필요한 상황은 거의 없다. 하지만 수정자 주입이나 일반 메소드 주입을 이용하면 불필요하게 수정의 가능성을 열어두어 유지보수성을 떨어뜨린다. 그러므로 생성자 주입을 통해 변경의 가능성을 배제하고 불변성을 보장하는 것이 좋다.
테스트가 특정 프레임워크에 의존적이다.
테스트가 특정 프레임워크에 의존하는 것은 침투적이므로 좋지 못하다. 그러므로 가능한 순수 자바로 테스트를 작성하는 것이 가장 좋은데, 생성자 주입이 아닌 다른 주입으로 작성된 코드는 순수한 자바 코드로 단위 테스트를 작성하는 것이 어렵다.
순수한 자바로 테스트 코드를 작성하는 것이 가장 좋다.
자바 스프링에서 의존성 주입 방식을 선택할 때 각 방식마다 장단점이 존재한다. 우선, Setter 주입을 사용하면 객체 생성 후에 의존성을 주입할 수 있는 유연함이 있지만, 이는 객체의 상태를 변경 가능하게 열어두는 단점이 있다. 즉, 외부에서 객체의 상태를 변경할 수 있어 코드의 불변성이 깨질 위험이 있다. 반면, @Autowired를 통해 의존성을 주입하면 스프링이 자동으로 의존성을 처리해주므로 편리하지만, 이 방식으로 테스트 코드를 작성할 경우 스프링 컨텍스트를 로드해야 한다. 이로 인해 단순한 단위 테스트가 아닌 통합 테스트로 변하게 되며, 스프링이 컴포넌트를 등록하고 초기화하는 데 시간이 소요되어 테스트 비용이 증가하는 단점이 있다. 또한, 리플렉션을 사용하면 객체의 메타 정보를 동적으로 수정할 수 있는 유연함이 있지만, 이는 테스트 코드가 깨지기 쉬운 구조가 되어 코드 안정성을 해칠 수 있다. 리플렉션은 코드가 변경될 때 의도치 않게 테스트가 실패할 가능성을 내포하고 있다. 이와 대조적으로, 생성자 주입을 사용하면 객체가 생성될 때 필요한 의존성을 명시적으로 주입받을 수 있으며, 주입해야 할 의존성이 누락된 경우 컴파일 시점에서 오류를 발견할 수 있는 장점이 있다. 또한, 테스트 코드 작성 시에는 의존성을 생성자 파라미터로 직접 전달할 수 있어, 스프링 컨텍스트를 로드하지 않고도 테스트를 수행할 수 있다. 이를 통해 테스트가 더 빠르고 안정적으로 이루어질 수 있다. 따라서 생성자 주입 방식은 컴파일 시점에 안정성을 보장하고, 테스트의 효율성과 편리함을 높이는 선택이 될 수 있다.
Reference
https://docs.spring.io/spring-framework/reference/core/beans/dependencies/factory-collaborators.html