의존성 주입이란?
Spring 프레임워크가 지원하는 핵심 프로그래밍 모델 중 하나로, 객체 간의 "의존 관계"를 빈 설정 정보를 바탕으로 컨테이너가 자동으로 연결해주는 것을 말한다.
A가 B를 의존하고 있다.
라고 하였을 때, 의존 대상인 B가 변화하면 그것이 A에 영향을 미친다면 그것을 "의존관계"라고 한다.
public class Cafe {
private Coffee coffee()
public Cafe() {
coffee = new Coffee();
}
public class Coffee {}
class Cafe가 class Coffee를 필드로 가질 때, Cafe는 Coffee에 의존하게 된다.
public class Cafe {
//컴파일 에러 발생
private Coffee coffee()
public Cafe() {
coffee = new Coffee();
}
public class Coffee2 {}
기존 Coffee 클래스의 이름이 Coffee2로 변경된다면, Coffee 클래스를 사용하던 다른 객체들도 함께 변경되어야 한다.
public class Cafe {
//상위 타입을 필드로 설정
private Coffee coffee()
//직접 객체를 생성하지 않고 생성자를 통해 전달 받음
public Cafe(Coffee coffee) {
this.coffee = coffee;
}
//상위 타입으로 사용할 인터페이스
public interface Coffee {}
//인터페이스 구현 클래스
public class Americano implements Coffee {}
앞의 방식들은 Cafe 클래스가 내부적으로 의존관계인 Coffee가 어떤 값을 가질지 "직접" 정하고 있다. 하지만, Spring의 DI는 그것을 외부에서 결정하고 자동으로 주입해준다.
1. 결합도가 줄어든다.
어떤 객체가 다른 객체에 의존한다는 것은, 그 의존 대상의 변화에 취약하다는 것이다. DI를 이용하면 주입받는 대상이 바뀔지 몰라도 해당 객체의 구현 자체를 수정할 일은 없어진다.
2. 재사용성이 높은 코드가 된다.
기존 Cafe 내부에서만 사용되었던 Coffee를 별도로 구분하여 구현하면, 다른 클래스에서 재사용할 수가 있다.
3. 테스트하기 좋은 코드가 된다.
DI를 이용한 객체를 자신이 의존하고 있는 인터페이스가 어떤 클래스로 구현되어 있는지 몰라도 된다. 따라서, 테스트하기 더 쉬워진다.
4. 가독성이 높아진다.
클래스 내의 기능들을 별도로 분리하게 되어 자연스레 가독성이 높아진다.
포스트에서는 Java Config 방식만 설명하고, XML Config 방식은 소개하지 않겠습니다 :)
변수 선언부에 @Autowired Annotation을 붙인다.
@Component
public class CafeController {
@Autowire
private CafeService cafeService;
}
set Method를 정의해서 사용한다.
@Component
public class CafeController {
private CafeService cafeService;
@Autowired
public void setCafeService(CafeService cafeService) {
this.cafeService = cafeService;
}
}
Constructor에 @Autowired Annotaion을 붙여 의존성을 주입받을 수 있다.
@Component
public class CafeService {
private CafeDAO cafeSDAO;
@Autowired
public setCafeService(CafeDAO cafeSDAO) {
this.CafeDAO = cafeSDAO;
}
}
@Component
public class CafeController {
private final CafeService cafeService = new CafeService(new CafeDAO());
Spring 4.3 버전 이후로는 생성자가 한 개 뿐이라면, @Autowired Annotation을 생략해도 자동으로 생성자 주입이 동작한다. 단, 생성자가 2개 이상일 경우에는 명시적으로 작성을 해주어야 한다.
객체가 생성될 때 모든 의존성이 주입되므로 의존성을 보장할 수 있다.
객체의 불변성을 보장할 수 있다.
코드 가독성이 좋다.
DI 컨테이너와의 결합도가 낮기 때문에 테스트하기 좋다.