1. 도입
대부분 Intellij에서 다음과 같은 경고 때문에 이 글을 보고 있을 확률이 높습니다.
왜 이럴까요?
Field Injection is not recommended ?
또한, 자세히 보면 인텔리제이는 다음과 같이 설명합니다.
항상 생성자 기반 DI를 사용하십시오. 필수적인 의존성에는 assertion을 쓰십니오
2. 의존성 주입의 종류
스프링 공식 레퍼런스에서는 Constructor Injection과 Setter Injection 두가지만을 소개하고 있지만,
실제로 의존성 주입은
•
생성자 기반 : Constructor-based dependency injection
•
세터 기반 : Setter-based dependency injection
•
필드 기반 : Field-based dependency injection
와 같이 3가지로 구분되며, 보통 마지막 Field Injection을 제일 많이 사용합니다.
2-1. Constructor Injection
@Component
public class BaseComponent {
private final BeanInjected bean;
@Autowired// 생략가능public BeanInjected(BeanInjected bean) {
this.bean = bean;
}
...
}
Java
복사
생성자 기반 DI의 장점은 빈 생성시점에 주입됨으로써,
주입받는 필드를 final로 상수 선언이 가능하다는 점입니다.이 점은 필수적인 디팬던시를 관리할때 편리합니다. (Required Dependencies)
스프링 4.3부터는 생성자 기반 DI에서 빈의 생성자가 하나만 있을 경우,
@Autowired 생략해도 자동으로 Injection됩니다..
추가로 Lombok의 @RequiredArgsConstructor까지 사용하면 깔끔하게 생성자까지 생략할 수 있습니다.
2-2. Setter Injection
@Component
public class BaseComponent {
private BeanInjected bean;
@Autowired
void setBean(BeanInjected bean) {
this.bean = bean;
}
...
}
Java
복사
Setter 기반 DI는 다음과 같이 setter메서드에 사용합니다.
여기서 @Autowired 애너테이션은 생략될 수 없으며,
빈 생성과 동시에 주입되지 않고, 빈 생성이 끝난 후 setter을 호출하여 주입합니다.
그렇기 때문에 final을 사용할 경우 컴파일 에러가 발생합니다.
2-3. Field Injection
@Component
public class BaseComponent {
@Autowired
private BeanInjected bean;
...
}
Java
복사
Field Injection은 프로젝트를 하면서 가장 자주 접하게되는 주입 방식입니다.
setter기반과 마찬가지로 빈 생성이 완료된 이후 주입되며, 마찬가지로 final로 선언할 수 없습니다.
하지만 앞선 다른 방식들과 다르게 간단하게 필드에 @Autowired같은 애너테이션만 달아주기 때문에매우 간결해보이며 유지보수에 편해보입니다.
하지만 IDE와 스프링팀에서 경고하듯이 몇가지 단점이 있으며,
이 때문에 Spring Document에도 기재되어 있지 않습니다.
3. Field Injection이 왜 나쁜가
1. 주입된 객체는 Immutable한 상태를 만들 수 없다.
오직 Constructor Injection 만이 final 선언이 가능합니다. 나머지 방법은 주입되는 필드에 대해 mutable한 상태를 만들기 때문에
가급적이면 생성자 주입을 적용하는게 좋습니다.
2. DI 컨테이너에 강한 결합 발생 !!!
Field Injection은 생성자를 통해서도, setter를 통해서도 주입을 받는 방식이 아닙니다.
그렇기 때문에 Spring이 아니면 해당 필드에 Injection을 할 수 있는 방법이 없습니다. ( 리플렉션 제외 )
즉, Spring DI 컨테이너 밖에서 작동할 수 없는 코드를 만듭니다.
이는 흔히 소프트웨어 공학에서 추구하는 loose coupling (결합도를 낮추고 응집도를 높이는 행위)와 반대됩니다.
3. SRP 위반 (Single Responsibility Principle)
사실 이부분에 저는 동의 하지 않습니다. 하지만 다른 곳에서는 Field injection이
객체지항의 원칙 SOLID중에서 단일 책임의 원칙에 위배된다고 합니다.
4. 결론 및 추천 방법
선택적인 의존성에서는 Setter Injection 를 사용하라고 합니다.
또한 Setter Injection은 실행 이후 다시 Injection을 할 수 있다는 장점이 있네요.아직 Opional한 의존성을 겪어보지는 못했으니, 웬만한 경우에는 생성자 기반 DI를 사용하면 될 듯합니다.