스프링(Spring)의 핵심: 의존성 주입(DI)과 제어의 역전(IoC)
1. 왜 이 개념이 중요한가?
스프링 프레임워크는 결국 두 가지 원칙 위에 세워졌다.
- 제어의 역전(IoC): 객체 생성, 생명주기 관리를 개발자가 아닌 프레임워크(SPRING)가 맡는다.
- 의존성 주입(DI): 필요한 의존 객체를 직접 생성하지 않고 외부에서 주입받는다.
이 두 개념을 통해 결합도는 낮추고, 유지보수성과 테스트 용이성은 크게 높일 수 있다.
2. 제어의 역전(IoC: Inversion of Control)
✅ 기존 방식 (제어 직접 수행)
1
2
3
4
5
6
7
| public class OrderService {
private OrderRepository repo = new OrderRepository(); // 직접 생성
public void order() {
repo.save();
}
}
|
- 문제:
OrderService
는 OrderRepository
구체 구현에 강하게 결합됨 - 테스트 시
OrderRepository
를 바꾸기 어려움
✅ IoC 방식 (제어권 위임)
1
2
3
4
5
6
7
| public class OrderService {
private OrderRepository repo;
public OrderService(OrderRepository repo) {
this.repo = repo;
}
}
|
OrderService
는 더 이상 객체 생성을 직접 하지 않음- 외부에서 어떤 구현체를 넘길지 “제어의 주도권”이 바뀜 → IoC
3. 의존성 주입(DI: Dependency Injection)
의존성 주입은 IoC의 구현 방법 중 하나로, 필요한 객체를 외부에서 주입받는다.
1) 생성자 주입 (가장 권장됨)
1
2
3
4
5
6
7
8
9
| @Component
public class OrderService {
private final OrderRepository repo;
@Autowired
public OrderService(OrderRepository repo) {
this.repo = repo;
}
}
|
2) 필드 주입 (테스트 어렵고 비추천)
1
2
3
4
5
| @Component
public class OrderService {
@Autowired
private OrderRepository repo;
}
|
3) 세터 주입 (선택적 의존성에 적합)
1
2
3
4
5
6
7
8
9
| @Component
public class OrderService {
private OrderRepository repo;
@Autowired
public void setRepo(OrderRepository repo) {
this.repo = repo;
}
}
|
4. Spring이 DI를 처리하는 방식
@Component
로 등록한 클래스는 스프링이 **빈(Bean)**으로 관리@Autowired
를 통해 의존 객체를 찾아서 주입ApplicationContext
가 이 모든 과정을 자동 수행
1
2
3
4
5
6
7
8
| @Configuration
@ComponentScan
public class AppConfig {}
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
OrderService service = ctx.getBean(OrderService.class);
}
|
5. 실무에서 이렇게 적용됨
✅ 예: MemberService
가 MemberRepository
를 사용
1
2
3
4
5
6
7
8
9
| @Service
public class MemberService {
private final MemberRepository repo;
@Autowired
public MemberService(MemberRepository repo) {
this.repo = repo;
}
}
|
MemberRepository
가 JPA 구현이든, 메모리 저장소든 주입만 바꾸면 됨- 테스트에서도 가짜(Mock) 객체 주입 가능 → 단위 테스트 용이
6. 장점 정리
항목 | 효과 |
---|
IoC | 객체 생성 책임이 프레임워크로 이동 → 결합도 낮춤 |
DI | 필요한 구현체를 외부에서 주입 → 테스트, 확장성 용이 |
객체지향 원칙 | DIP(의존 역전), OCP(개방-폐쇄) 원칙 충족 |
7. 결론
Spring의 DI와 IoC는 단순히 문법이 아니라, 유지보수 가능한 구조를 만들기 위한 철학과 구조 설계 방식이다. 이 개념을 이해하고 쓰지 않으면 Spring은 그냥 무거운 컨테이너일 뿐이다. 핵심은 “내가 객체를 만들지 않는다”, **“필요한 건 외부에서 주입받는다”**는 두 가지 원칙이다.