[Spring] Spring 핵심 원리 : 생성자 주입을 사용해야 하는 이유
불변
대부분의 의존관계는 한번 주입되면 애플리케이션의 종료 시점까지 변경될 일이 없다. 오히려 의존관계는 변하지 않아야 한다. 그리고 생성자는 객체 생성 시점에 단 1회만 호출되고, 이후에 의존관계를 변경할 수 없다. 따라서 생성자 주입은 객체의 불변성을 보장할 수 있다.
필수
순수한 Java 코드로 테스트를 진행하는 경우, setter 메서드 주입을 사용했다면 테스트 코드는 다음과 같을 것이다.
@Test
void signUp() {
MemberService memberService = new MemberServiceImpl();
memberService.signUp(new Member(1L,"userA",Grade.VIP));
}
그러나 NullPointException 예외가 발생할 것이다. MemberRepository를 주입하는 것을 누락했기 때문이다. 그러나 생성자 주입을 사용하면 MemberServiceImpl을 생성할 때, 필요한 객체를 매개변수로 전달할 것을 문법적으로 강제한다. 따라서 의존관계에 필요한 객체가 누락되었을 경우 컴파일 에러로 발견할 수 있고, 어떤 객체를 필수로 주입해야 하는지 알 수 있다.
final 키워드
생성자 주입을 사용하는 경우에만 필드에 final 키워드를 사용할 수 있다. 그 외에 setter 메서드 주입이나 필드 주입을 사용하면 final 키워드를 사용할 수 없다. 그래서 생성자에서 값을 설정하지 않았다면 컴파일 시점에 이를 잡을 수 있다.
다음과 같이 생성자 메서드에 의존 객체 주입을 누락한다면 Variable 'discountPolicy' might not have been initialized와 같은 컴파일 에러가 발생한다.
public class OrderServiceImpl implements OrderService {
private final OrderRepository orderRepository;
private final MemberRepository memberRepository;
// Variable 'discountPolicy' might not have been initialized
private final DiscountPolicy discountPolicy;
@Autowired
public OrderServiceImpl(OrderRepository orderRepository, MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.orderRepository = orderRepository;
this.memberRepository = memberRepository;
// this.discountPolicy = discountPolicy;
}
}
정리
생성자 주입은 프레임워크에 의존하지 않고 순수한 Java 언어의 특징을 잘 살리는 방법이다. 기본적으로 생성자 주입을 사용하고 필수 값이 아닌 경우 setter 메서드 주입 방식을 옵션으로 선택하면 된다. 필드 주입은 사용하지 않는 게 좋다.