Spring의 IoC와 DI를 어떻게 이해할 것인가
IoC와 DI는 왜 중요한가
스프링을 배울 때 가장 먼저 듣는 개념이 IoC와 DI다. 그런데 용어만 외우면 실전에서 감이 잘 오지 않는다. 핵심은 “객체가 스스로 의존 대상을 만들고 실행 흐름을 통제하지 않는다”는 점이다.
DI 먼저 이해하는 편이 쉽다
의존이란
한 클래스가 다른 클래스의 기능에 기대고 있으면 의존 관계가 있다고 본다. 문제는 이 의존이 구체 클래스에 직접 묶일 때다.
1
2
3
public class OrderService {
private final PaymentClient paymentClient = new KakaoPayClient();
}
이 구조는 교체가 어렵고 테스트도 불편하다.
DI란
필요한 의존 객체를 직접 생성하지 않고 외부에서 주입받는 방식이다.
1
2
3
4
5
6
7
public class OrderService {
private final PaymentClient paymentClient;
public OrderService(PaymentClient paymentClient) {
this.paymentClient = paymentClient;
}
}
이렇게 하면 구현체를 바꾸기 쉬워지고, 테스트 더블 주입도 쉬워진다.
IoC는 더 큰 개념이다
IoC는 제어권이 애플리케이션 코드에서 컨테이너로 넘어가는 것을 말한다.
예전에는 main()에서 객체를 만들고 연결하고 호출 순서도 직접 정했다. 스프링에서는 컨테이너가 빈을 만들고 의존성을 연결하고 생명주기를 관리한다. 개발자는 어떤 빈이 필요하고 어떻게 협력해야 하는지만 선언한다.
즉:
- DI: 의존성을 주입하는 구체적 기법
- IoC: 제어 흐름이 컨테이너에 역전된 더 큰 개념
왜 생성자 주입을 권장하는가
- 필수 의존성을 강제할 수 있다.
- 불변 필드 사용이 쉽다.
- 테스트가 단순하다.
- 순환 참조가 빨리 드러난다.
필드 주입보다 생성자 주입이 더 명시적이고 안전하다.
실무에서 흔한 오해
- 스프링 빈이면 자동으로 좋은 설계라고 생각함
@Autowired만 붙이면 DI를 이해한 것처럼 느껴짐- 프레임워크에 강하게 묶인 코드도 괜찮다고 여김
좋은 설계는 스프링 애너테이션을 떼어내도 역할이 설명되는 구조여야 한다.
정리
IoC와 DI의 핵심은 “객체가 혼자 다 하지 않게 만드는 것”이다. 스프링은 이를 컨테이너 차원에서 지원하고, 개발자는 그 위에서 결합도를 낮추고 테스트하기 쉬운 구조를 만들 수 있다.
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.
댓글
아직 댓글이 없습니다