🔁 IOC(제어의 역전, Inversion Of Control)란?
- 객체의 생성과 제어 권한을 개발자가 아닌 Spring Container가 가져가는 개념
- 직접 new로 만들지 않고 Spring이 대신 만들어서 관리
📚 IOC의 역할

👨🍳 비유: 셰프가 요리 재료를 준비
| 직접 제어 (전통적) | 제어 역전 (IOC) |
|---|---|
| 개발자가 객체 생성 | Spring이 생성 |
| 개발자가 의존성 주입 | Spring이 자동으로 주입 |
🔧 IOC 개념 요약
🤝 DI (Dependency Injection, 의존성 주입)란?
- 객체 간의 의존성을 Spring이 대신 연결해주는 기술
- 개발자가 직접 new 하지 않고, 필요한 객체를 Spring이 주입해 줌
📚 DI의 역할

🍳 비유: 셰프가 재료를 요리사에게 전달
📌 DI가 필요한 이유
🗂️ DI 방식 요약
| 방식 | 예시 | 특징 |
|---|---|---|
| 생성자 주입 | @Autowired 생성자 사용 | 가장 권장됨 |
| 필드 주입 | 필드 위에 @Autowired | 테스트 불편, 권장 안 함 |
| 세터 주입 | @Autowired 세터 메서드 | 선택적 주입에 적합 |
🧩 IOC/DI 정리 요약
| 항목 | 설명 |
|---|---|
| IOC (제어의 역전) | 객체 생성/관리를 Spring이 대신함 |
| DI (의존성 주입) | 필요한 객체를 자동으로 주입함 |
| 목적 | 코드의 결합도↓, 유연성↑, 재사용성↑ |
| 구현 방식 | 생성자 주입, 필드 주입, 세터 주입 등 |
✅ IOC/DI의 장점
| 장점 | 설명 |
|---|---|
| 유연한 구조 | 구현체만 바꿔도 코드 변경 없음 |
| 유지 보수 용이 | 의존 객체 교체가 쉬움 |
| 테스트 편리 | Mock 객체 등으로 대체 가능 |
| 모듈화 용이 | 책임 분리가 명확해짐 |
❌ 직접 객체를 관리할 경우 (전통적 방식)
MyRepository repo = new MyRepositoryImpl(); // 직접 생성
MyService service = new MyServiceImpl(repo); // 강한 결합
→ MyRepositoryImplV2로 변경 시 main() 코드를 직접 고쳐야 함
→ 클래스 간 결합도가 높아짐 → 유지 보수 어려움
✅ Spring이 객체를 주입할 경우 (IOC + DI 적용)
@Service
public class MyIocService implements MyService {
private final MyRepository myRepository;
@Autowired // 생성자 주입
public MyIocService(MyRepository myRepository) {
this.myRepository = myRepository;
}
}
@Repository
public class MyIocRepository implements MyRepository {
public void queryDatabase() {
System.out.println("쿼리 실행");
}
}
@ComponentScan(basePackages = "com.example")
public class MyIocApp {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(MyIocApp.class);
MyService service = context.getBean(MyService.class);
service.doSomething();
}
}
→ MyIocRepositoryV2가 새로 생겨도 서비스 코드는 변경 없이 교체 가능
→ Bean으로 등록만 바꾸면 됨 (ex. @Primary 사용 등)
🎯 한눈에 보는 핵심 흐름
개발자는 인터페이스만 정의
구현체는 @Component, @Service, @Repository로 등록
Spring Container가 자동으로 생성/주입
코드는 변화 없이 실행됨 (확장성 ↑)