Spring 프레임워크가 지원하는 3가지 핵심 프로그래밍 모델 중 하나이다.
외부에서 두 객체 간의 관계를 결정해주는 디자인 패턴으로, 인터페이스를 사이에 둬서 클래스 레벨에서는 의존관계가 고정되지 않도록 하고 런타임 시에 관계를 동적으로 주입하여 유연성을 확보하고 결합도를 낮출 수 있게 해준다.
의존성이란 한 객체가 다른 객체를 사용할 때 의존성이 있다고 한다.
public class Store {
private Pencil pencil;
} // Store 객체는 Pencil 객체에 의존한다(의존성이 있다).
의존 관계 설정이 컴파일시가 아닌 실행시에 이루어져 모듈들간의 결합도를 낮출 수 있다.
코드 재사용을 높여서 작성된 모듈을 여러 곳에서 소스코드의 수정 없이 사용할 수 있다.
모의 객체 등을 이용한 단위 테스트의 편의성을 높여준다.
@Controller
public class BookController {
private final BookService bookService;
public BookController(BookService bookService) {
this.bookService = bookService;
}
}
생성자 주입은 생성자에 의존성 주입을 받고자 하는 field를 나열하는 방법으로, 가장 권고되는 방법이다.
장점
필수적으로 사용해야 하는 레퍼런스 없이는 인스턴스를 만들지 못하도록 강제함
Spring 4.3 이상부터는 생성자가 하나인 경우 @Autowired 를 사용하지 않아도 됨
Circular Dependency / 순환 참조2 의존성을 알아 차릴 수 있음
생성자에 점차 많은 의존성이 추가 될 경우 리패토링 시점을 감지 할 수 있음
의존성 주입 대상 필드를 final로 불변 객체 선언할 수 있음
테스트 코드 작성시 생성자를 통해 의존성 주입이 용이함
단점
어쩔 수 없는 순환 참조는 생성자 주입으로 해결하기 어려움
이 경우에는 나머지 주입 방법을 사용하도록 하나 순환참조가 발생하지 않도록 하는 것이 더욱 중요
@Controller
public class BookController {
@Autowired
private BookService bookService;
}
멤버 필드에 @Autowired 어노테이션을 선언하여 주입받는 방법이다.
장점
단점
의존 관계가 눈에 잘 보이지 않고 추상적이며 의존성 관계가 과도하게 복잡해질 수 있음
DI Container와 강한 결합을 가져 외부 사용이 용이하지 않음(단위 테스트시 의존성 주입이 용이하지 않음)
의존성 주입 대상 필드가 final 선언 불가
@Controller
public class BookController {
private BookService bookService;
@Autowired
public void setBookService(BookRepository bookService) {
this.bookService = bookService;
}
}
setter 메서드에 @Autowired annotation을 선언하여 주입받는 방법이다.
장점
의존성이 선택적으로 필요한 경우에 사용
생성자에 모든 의존성을 기술하면 과도하게 복잡해질 수 있는 것을 선택적으로 나눠 주입 할 수 있게 부담을 덜어줌
생성자 주입 방법과 Setter 주입 방법을 적절하게 상황에 맞게 분배하여 사용
단점