Dependency Inject

개발자가 객체간 의존성을 직접 호출하는 대신 스프링 컨테이너에서 생성하여 넣어주는 방식
인터페이스를 사이에 두어 클래스 레벨에서 의존관계가 고정되지 않고, 런타임 시 관계를 동적으로 주입하여 유연성을 확보하고 결합도를 낮춘다.
의존성 주입에 사용되는 Annotation 에는 @Autowired, @Inject, @Resource가 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Controller {

private Service service = new Service(); // 직접 호출

//만약, Service 의 객체를 Service2() 로 교체해야 한다면,
//Service 를 의존하는 모든 클래스를 수정해주어야 한다.
//해당 문제를 해결하기 위해 DI 를 사용한다.

void test() {
service.test();
}

}
1
2
3
4
5
6
7
8
9
10
11
12
public class Controller {

//Controller 는 Service 에게 의존한다.
private Service service;

//1. 생성자 주입
@Autowired
public Controller (Service serv) {
this.service = serv;
}

}

Spring 4.3 ~ 클래스 내 생성자는 단일
생성자로 주입 받을 객체가 Bean 으로 등록되어 있다면 Autowired Annotation 생략 가능
1회 호출 보장 주입 받은 객체가 변하지 않거나, 반드시 객체 주입이 필요한 경우 강제하기 위해 사용

1
2
3
4
5
6
7
public class Controller {

//2. 필드 주입
@Autowired
private Service service;

}

코드가 굉장히 간결하지만 의존관계를 파악하기 힘듦
주입이 동시에 일어나 겹치는 경우 순환 참조 문제 발생

1
2
3
4
5
6
7
8
9
10
11
public class Controller {

private Service service;

//3. 수정자 주입 (setter)
@Autowired
public setService(Service serv) {
this.service = serv;
}

}

setter 혹은 사용자 정의 메소드를 통해 의존관계 주입

각 주입 방식에 따라 순환참조 문제가 발생하는 시점이 다른데, 필드 주입과 수정자 주입은 런타임 시 발생하고 생성자 주입 방식은 컴파일 시 발생한다.
즉, 개발자가 먼저 대처하기 편한 방식은 생성자 주입 방식이다.


순환 참조: A객체는 B객체를 참조하고, B객체는 A객체를 참조 (서로 동시에 참조하고 있을때 발생)