이 글을 작성하기 위해 주입받은 포스트는 다음과 같다.
yaboong.github.io/spring/2019/08/29/why-field-injection-is-bad/
이번 공부용 프로젝트를 만들면서 test code를 제외한 모든 코드에 @Autowired를 사용하지 않았다.
필드 주입 대신 생생자 주입을 사용하는 이유는 순환 의존을 방지해서 안전하다 등 어렴풋이만 알고 있었는데 확실하게 정리해보자.
필드 주입을 사용하면 생기는 문제는 다음과 같다.
첫 번째로 의존 관계를 final로 설정할 수 없다. 런타임에 객체의 의존성이 바뀌는 경우는 흔치 않다.
필드를 final로 선언한다면 런타임시 의존성이 바뀌어 원하지 않는 결과가 나오는 일을 방지할 수 있다.
두번째로 필드 주입을 사용하면 스프링 프레임워크, 특히 컨텍스트 (빈 컨테이너)에 강한 의존성이 생긴다. 거대한 애플리케이션에서 테스트는 매우 중요하다. 스프링에 의존적하지 않는 단위 테스트 작성 시 필드 주입을 이용하는 의존관계 주입은 컨텍스트를 사용하지 않고서는 의존성을 주입할 방법이 없다.
세번째로 생성자나 Setter에 의해 의존성이 명확하게 나타나지 않아 코드의 가독성이 떨어진다. 물론 이는 롬복을 사용한 주입에서도 마찬가지이기 때문에 큰 문제는 아니다.
가장 중요한 네번째는 필드 주입은 순환 의존을 애플리케이션 구동 시에 에러를 발견하지 못한다.
예를들어 객체 A는 객체 B에 의존하고 객체 B는 객체 A에 의존한다 해보자. A와 B가 모두 빈으로 등록이 된다면 각각의 필드에 B와 A의 레퍼런스가 주입된다. 컴파일도 됐고 스프링 애플리케이션 구동까지 모두 성공적으로 됐다. 이 때, A의 메서드인 a가 객체 B의 메서드 b를 사용하고, b는 다시 a의 메서드를 호출한다면 순환 의존이 생겨 런타임 에러가 발생한다.
생성자 주입을 사용하는 경우, 차례대로 빈을 생성하면서 주입을 한다. A를 생성할 때 B를 생성해 주입하려는데 B에 주입되어야 하는 A는 이미 생성이 되어있다. 이미 생성이 되어 있다는 것은 순환 의존이 있다는 것이다. 만약 순환 의존이 없다면 B를 생성하는 시점에 주입되는 객체들은 이미 생성이 되어 있지 않아야 한다. 이렇게 애플리케이션이 구동되기 전 순환 의존을 탐지해서 서비스 중단을 피할 수 있다.