DI란 Dependency Injection의 줄임말로, 의존성 주입이다.
Spring 프레임워크는 3가지 핵심 프로그래밍 모델을 지원하는데, 그 중 하나가 의존성 주입(DI)이다. DI란 외부에서 두 객체 간의 관계를 결정해주는 디자인 패턴으로, 느슨한 결합을 하게 해준다.
"A가 B를 의존한다." 의 의미는 다음과 같다.
객체 내부에서 다른 객체를 생성하는 것은 강한 결합도를 가지는 구조이다.
아래의 예제에서 Pencil을 판매하는 Store가 있다고 할 때, Store에서 다른 Computer와 같은 상품을 판매하기 위해서는 Store 클래스를 수정해야하는 문제점이 있다.
public class Store {
private Pencil pencil;
public Store(){
this.pencil = new Pencil();
{
}
객체를 주입 받는다는 것은 외부에서 생성된 객체를 인터페이스를 통해서 넘겨받는 것이다. 이렇게 하면 결합도를 낮출 수 있고, 런타임시에 의존관계가 동적으로 주입되어 유연한 구조를 가진다.
public interface Product {}
public class Pencil implements Product {}
public class Computer implements Product {}
public class Store {
private Product product;
public Store(Product product) {
this.product = product;
}
}
public class Main {
public static void main(String[] args) {
// Store store = new Store(); // 컴파일 에러
Store store1 = new Store(new Pencil());
Store store2 = new Store(new Computer());
이를 이용하면 Store에서는 상품이 변경되어도 Store 클래스는 수정이 없고, 생성할 때 Product를 구현한 클래스만 주입해주면 된다.
의존성 주입에는 생성자 주입, 필드 주입, 수정자 (setter) 주입 등이 있으며 생성자 주입을 강력히 권장한다.
필드에 @Autowired
어노테이션만 붙여주면 자동을 의존성 주입이 된다. 사용법이 매우 간단하다. 하지만,
public class Store {
@Autowired
private Product product;
}
setter 주입은 런타임시에 할 수 있도록 낮은 결합도를 가지게 구현되었다. 하지만,
NullPointerException
이 발생한다.public class Store {
private Product product;
public void setProduct (Product product) {
this.product = product;
}
}
public class Main {
public static void main(String[] args) {
Store store = new Store();
store.setProduct(new Pencil());
store.setProduct(new Computer()); //바꿀 수 있다.
Store store2 = new Store(); //그냥 만들 수도 있다.
생성자 주입의 경우
null을 주입하지 않는 한 NullPointerException은 발생하지 않는다.
의존관계를 주입하지 않은 경우에는 객체를 생성할 수 없다. 즉, 의존관계를 외부로 노출시킴으로써 컴파일 타임에 오류를 잡아낼 수 있다.
final을 사용할 수 있다. final로 선언된 레퍼런스타입 변수는 반드시 선언과 함께 초기화가 되어야 하므로 setter 주입시에는 의존관계를 주입받을 필드에 final을 사용할 수 없다.
생성자 주입을 하면 객체 간 순환참조를 하고 있는 경우 스프링 어플리케이션이 구동되지 않는다. 컨테이너가 빈을 생성한느 시점에서 객체생성에 사이클관계가 생기기 때문이다.
(setter 주입 시 구동은 되지만 순환참조를 하고 있는 부분에 호출이 생기면 StackOverFlowError가 생긴다.)
테스트 코드 작성하기 좋다.
(필드 주입 시 객체를 생성해서 주입할 수가 없다.)
참고 : https://yaboong.github.io/spring/2019/08/29/why-field-injection-is-bad/
https://mangkyu.tistory.com/150