스프링 프레임워크에서는 3갸지 의존성 주입 방식이 있다.
1. field injection (필드 주입)
2. constructor injection (생성자 주입)
3. setter injection (setter 주입)
클래스 멤버변수에 직접 의존성 주입
코드가 간결하고, 쉽게 사용 가능
@Component
public class Injection {
@Autowired
private FieldInjection fieldInjection;
}
Setter 메서드로 의존성 주입
객체 생성 후 의존성 주입 -> 객체 생성과 의존성 주입 분리
@Component
public class Injection {
private SetterInjection setterInjection;
@Autowired
public void setSetterInjection(SetterInjection setterInjection) {
this.setterInjection = setterInjection;
}
}
객체를 생성 시 생성자를 통해 의존성 주입
객체 생성과 동시에 의존성 주입
@Component
public class Injection {
private final ConstructorInjection constructorInjection;
// @Autowired 주입받을 객체가 빈으로 등록되어있고 생성자가 하나면 생략 가능
public Injection(ConstructorInjection constructorInjection) {
this.constructorInjection = constructorInjection;
}
public void doSomething() {
}
}
2개 이상의 생성자가 있을 경우 @Autowired 붙여줘야함
다른 주입과 달리 필드 final 선언 가능
스프링에서는 생성자 주입 방식 사용을 추천함
@Component
public class Injection {
@Autowired
private FieldInjection fieldInjection;
@Autowired
private FieldInjection2 fieldInjection2;
@Autowired
private FieldInjection3 fieldInjection3;
@Autowired
private FieldInjection4 fieldInjection4;
@Autowired
private FieldInjection5 fieldInjection5;
...
}
// 생성자 주입으로 바꾸면
@Component
public class Injection {
private final FieldInjction fieldInjection;
private final FieldInjction2 fieldInjection2;
private final FieldInjction3 fieldInjection3;
private final FieldInjction4 fieldInjection4;
private final FieldInjction5 fieldInjection5;
...
public Injection(FieldInjction fieldInjection,
FieldInjction2 fieldInjection2,
FieldInjction3 fieldInjection3,
FieldInjction4 fieldInjection4,
FieldInjction5 fieldInjection5,...) {
this.fieldInjection = fieldInjection
this.fieldInjection2 = fieldInjection2
this.fieldInjection3 = fieldInjection3
this.fieldInjection4 = fieldInjection4
this.fieldInjection5 = fieldInjection5
...
}
}
@Autowired만 붙이면 되기 떄문에 너무 많은 의존이 생김
DI 컨테이너를 사용하면 외부에서 의존관계를 주입시켜 주기 때문에 객체 스스로 의존성에 대한 책임이 없어지게 된다. 그럼 필요한 의존성에 대한 정보를 제공해야 함. setter와 생성자 주입의 경우 무엇을 선택사항으로 받는지, 필요로 하는지 명확히 제공해주고 있지만 field주입의 경우 숨은 의존성만 제공하고 있음
스프링의 DI 컨테이너는 의존하는 bean 간에 느슨한 결합을 제공해주는 반면@Autowired를 이용한 필드 인젝션을 하면 스프링을 통해서만 의존성 주입이 가능하기 때문에 해당 Bean들이 스프링의 DI 컨테이너와의 강한 결합을 하게 된다.
final 선언으로 불변성 보장
필드주입이나 setter주입은 빈 생성 후 참조를 하기 때문에 서버 동작 후에 순환참조 코드가 호출되면 서버가 죽는다. 실제 구동 전까지는 문제를 알 수 없음.
생성자 주입은 인자로 사용되는 빈을 찾거나 빈 팩토리에서 생성 후 찾아서 주입하려는 빈의 생성자를 호출함. 주입하려는 빈을 먼저 찾고 객체 생성 시점에 빈을 주입하기 떄문에 참조하는 객체가 생성되지 않은 상태에서 참조하게 되어 서버 구동 전에 BeanCurrentlyInCreationException
오류가 발생함.
순환 참조뿐만 아니라 의존 관계에 내용을 외부로 노출시킴으로써 애플리케이션을 실행하는 시점에서 오류를 체크할 수 있음
필드주입이나 세터주입은 mockito로 모킹 후 테스트를 진행해야 하는데 생성자주입은 객체 생성 후 생성자에 넣어주면 됨.
public class InjectionTest {
@Test
public void test() {
ConstructorInjection ci = new ConstructorInjection();
Injection injecion = new Injection(ci);
injection.doSomething();
}
}
https://shanepark.tistory.com/368
https://jackjeong.tistory.com/entry/Spring-%EC%83%9D%EC%84%B1%EC%9E%90-%EC%A3%BC%EC%9E%85-vs-%ED%95%84%EB%93%9C-%EC%A3%BC%EC%9E%85-Autowired
https://nect2r.tistory.com/58