스프링 프레임워크를 사용하며 의존 관계 주입 방법이 여러가지가 있는 것을 알았다. 왜 스프링은 이렇게 여러 가지 방법들을 만들어놨고, 각각 어떠한 차이가 있는지 궁금했다.
setter 수정자 메서드를 이용해서 의존관계를 주입 또는 변경하는 방법이다.
@Controller
public class MyController {
private MyService service;
...
public void setService(MyService service) {
this.service = service;
}
}
하지만 일반 자바 코드에서도 setter를 열어두게 되면 변경이 어디서 일어나는지 관리가 안되는 단점이 있듯이 마찬가지 단점이 적용된다. 불필요하게 수정의 가능성을 열어두게 된다.
또한 처음 객체를 생성했을 때 필요한 의존 관계가 완전히 주입되지 않을 수 있어 NullPointerException 같은 예외로부터 안전하지 못하다.
공식문서에 따르면 기본적으로 setter를 통한 의존성 주입을 지양해야 하지만, 상호 참조 같은 문제가 있을 때는 setter를 통해서 해결할 수 있다.
하지만 애초에 생성자 방식을 사용할 때 순환참조가 발생하면 애플리케이션 구동 시점에 에러가 발생해서 예방 가능하다.
이름 그대로 필드에 바로 주입하는 방법이다.
@Controller
public class MyController {
@Autowired
private MyService myService;
...
}
코드가 간결하다는 장점이 있지만 외부에서 변경이 불가능해서 테스트 하기 힘들다. 또한 DI 프레임워크에 굉장히 의존적이다.
빈 객체를 생성하는 시점에 모든 의존 관계를 주입하는 것이다.
@Controller
public class MyController {
private final MyService myService;
public MyController(MyService myService) {
this.myService = myService;
}
}
생성자 호출 시점에 한번만 호출된다. 스프링 4.3 부터는 생성자가 하나이면 @Autowired
애노테이션을 붙이지 않아도 된다. setter를 사용하지 않으므로 불변성을 보장해주는 효과가 있다.
세 종류의 의존성 주입 설정 방법이 있지만, 생성자를 통한 방식이 다른 방식들 보다 낫다.