Spring Framework DI(Dependency Injection)이란?
스프링 프레임워크에서는 DI, IOC, AOP 등이 사용되고 있다. 이번에는 스프링 프레임워크에서 사용하는 DI Dependency Injection, 의존주입에 대해서 포스팅 해보려 한다.
의존 주입이라고 하면 영어를 직역한 표현같이 뭔가 잘 이해가 되질 않는다. 자바에서는 객체를 사용하고 이 객체를 다른 클레스에서 사용하려면 객체를 new 클레스이름 을 통해 생성해서 사용해야 한다.
DI는 이 new를 통해 생성하는 부분을 자동으로 해준다 생각하면 편할 것 같다. 기본적인 개념은 객체를 직접 생성하는 것이 아니라 자동으로 생성되는 것이다.
예를 들어 A라는 객체는 B, C클레스에서 사용된다 했을 때 B, C클레스는 A 객체를 받아와 사용하게 된다.

여기서 우리가 JAVA를 사용할때 객체를 외부에서 사용할때 new 키워드를 사용하게 된다. 스프링에서는 DI를 이용해 객체를 주입 받는데 이것을 오늘 알아보자.
스프링은 코드의 수정을 최소화 하고 유연한 사용을 위해 강한 결합을 피하고 느슨한 결합을 지향한다. 스프링은 class와 class간의 관계를 지양하려 한다. 객체와 객체간의 관계를 권장하며 상속의 경우 코드 작성의 제약이 많고 확장성을 떨어트려 피하는 것이 좋다. 그걸 위한 기법이 DI이다.
DI를 사용하기 위한 기법은 3가지가 있다. 생성자 주입, 필드 주입, 수정자 주입이다.
필드 주입
필드 주입은 빈으로 등록하는 객체를 다음과 같은 코드를 통해 주입해 사용한다.
public class Controller{
@Autowired
private Service service;
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
service.services .....
}
}
위의 코드를 보면 Service 객체를 @Autowired를 통해 주입받아 사용한다. 이처럼 엄청난 코드 간결성과 편의성 때문에 필자 뿐만 아니라 다른 회사에서도 많이 썼던 기법이라고 한다.
필자는 코드의 간결성과 유연성을 위해 필드 주입을 주로 사용했는데, 스프링에서는 필드주입을 권장하지 않는다. 그 이유는 개발을 진행하다 보면 여러 서비스 객체들이 생기는데 이러한 객체들이 필드 주입으로 인해 순환 참조될 수 있기 때문이다. 예를 들어 A는 B를 참조하고 B는 C를 참조하는데 C가 A를 참조할 경우 계속적으로 참조를 위해 사이클을 돌다가 스텍 에러를 띄우게 된다. 필자는 아직 경험해 본적이 없지만 이러한 문제를 아직 직면하지 않았지만 5버전 스프링에서는 이러한 문제 때문에 생성자 주입을 권장한다.
수정자 주입
수정자 주입방법은 setter를 이용한다. 예시는 다음과 같다
public class Controller{
private Service service;
@Autowired
public void setService(Service service){
this.service = service;
}
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
service.services .....
}
}
위와같이 Setter 수정자를 통해 사용하고자 하는 클레스에 객체를 주입 받았다. 이러한 방법은 의존관계 불변성을 위반할 수 있고, putlic 키워드로 메서드를 열어두기 때문에 좋은 방법이 아니다.
생성자 주입
생성자 주입 기법은 스프링에서 가장 권장하고 있는 DI 방법이다. Lombok 라이브러리와 사용성이 용이하고 생성자 호출 시점에서 딱 1번 호출하고 final 키워드 사용이 가능해 불변성을 만족한다. 또한 주입할 데이터가 누락되어있을 경우 컴파일 오류를 띄워준다.
예제는 다음과 같다.
public class Controller{
private final Service service;
@Autowired
public Controller(Service service) {
this.service = service
}
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
service.services .....
}
}