1. 생성자 주입 (Constructor Injection)
- 의존성 주입 방식 : 의존성을 주입할 때 클래스의 생성자를 통해 주입하는 방법
- 장점 :
- 불변성 보장 : 의존성 객체를 생성 시점에 한 번만 설정할 수 있으므로 객체가 불변으로 유지된다.
- 테스트 용이성 : 생성자 주입 방식은 객체를 주입하지 않고도 모의 객체(Mock)을 쉽게 주입하여 단위 테스트가 용이.
- 순환 의존성 방지 : 생성자 주입은 객체를 생성할 때 의존성 주입을 강제하기 때문에 컴파일 시점에 순환 의존성을 쉽게 감지할 수 있다.
- 필수 의존성 명시 : 생성자 주입은 필수적인 의존성을 강제하기 때문에 주입하지 않으면 컴파일 에러가 발생한다.
2. @Autowried 주입:
- 의존성 주입 방식: Spring이 제공하는 어노테이션으로, 의존성 주입을 필드, 생성자, 또는 메서드에 할 수 있음. 기본적으로는 필드에 직접 주입하는 방식으로 많이 사용됨.
- 장점:
- 간결함: 필드에 어노테이션을 붙이면 즉시 주입이 가능해 코드가 간단해짐.
- 단점:
- 테스트 어려움: 필드 주입 방식은 테스트에서 의존성을 모킹(Mock)하기 어려움.
- 불변성 약화: 객체 생성 후에 의존성을 주입하는 방식이므로, 주입 후에 의존성을 변경할 수 있어 객체가 불변성을 가지지 않음.
- 순환 의존성 문제: @Autowired를 남용하면 순환 의존성이 발생할 가능성이 있으며, 이를 런타임 시점에서야 발견할 수 있음.
- 프로퍼티 주입 비추천: Spring의 공식 가이드에서도 필드 주입은 되도록 피하라고 권장하는데, 이는 코드의 가독성과 유지보수성이 떨어질 수 있기 때문임.
@Autowired로 발생할 수 있는 문제점:
- 테스트 어려움: 필드에 주입된 의존성을 쉽게 교체할 수 없기 때문에 유닛 테스트 작성이 어려움.
- 순환 의존성 문제: 필드 주입 방식에서는 두 개 이상의 빈이 서로를 참조할 때 순환 의존성이 생기기 쉽고, 이는 런타임 오류를 발생시킬 수 있음.
- 불변성 결여: 객체가 생성된 후에 의존성이 주입되므로, 객체의 상태가 변경될 가능성이 있어 코드 안정성이 떨어짐.
필드 주입 방식에서 의존성 주입 시점:
필드 주입(@Autowired)을 사용할 경우, Spring 컨테이너가 객체를 생성하고 나서 주입이 이루어집니다. 즉, 객체가 생성된 후, 해당 객체의 의존성들이 필드에 주입되며, 이는 런타임 시점에 발생합니다.
따라서 객체가 완전하게 초기화되기 전에 의존성이 주입되지 않은 상태일 수 있으며, 이로 인해 불완전한 객체 상태에서 의존성에 접근하면 NullPointerException 같은 런타임 오류가 발생할 수 있습니다. 이러한 이유 때문에 생성자 주입이 더 안전하고 권장됩니다.