[IoC] Inversion of Control (제어의 역전)
정의
- 객체의 생성과 생명주기 관리의 제어권을 개발자가 아닌 Spring 컨테이너가 맡는 것.
- 개발자는 객체를 직접 생성(new)하지 않고, 컨테이너가 알아서 생성·관리된 객체(Bean)를 사용.
목적
- 객체 관리의 일관성 확보
- 중복 인스턴스 생성 방지 (메모리 낭비 ↓)
- 객체 충돌/의존성 꼬임 방지
스프링 컨테이너
- BeanFactory, ApplicationContext → 스프링이 제공하는 IoC 컨테이너
- 빈(bean)들을 생성, 의존성 주입, 소멸까지 전 주기를 관리
- 주요 어노테이션 (빈 등록)
- @Component : 일반적인 컴포넌트 등록
- @Controller / @RestController : MVC의 Controller 등록
- @Service : 서비스 계층 등록
- @Repository : DAO/DB 계층 등록
- @Configuration : 설정 클래스 등록
- 전부 @Component의 특수화(메타 어노테이션)
[DI] Dependency Injection (의존성 주입)
정의
- 필요한 객체(의존성)를 개발자가 직접 생성하지 않고, Spring 컨테이너가 알아서 주입해주는 기법.
목적
- 객체 간 결합도 ↓, 유연성 ↑
- 테스트 용이성 ↑ (mock 객체 주입 가능)
- 유지보수성 향상
주요 어노테이션
- @Autowired : 타입 기준으로 컨테이너에서 Bean을 찾아 주입
- @Qualifier("이름") : 같은 타입의 Bean이 여러 개일 때 특정 Bean 선택
- @Inject, @Resource : 자바 표준 DI 어노테이션 (Spring에서도 사용 가능)
DI 주입 방법
1) 필드 주입 (간단하지만 비권장)
@Autowired private BoardDao boardDao;
2) 생성자 주입 (권장)
private final BoardDao boardDao;
@Autowired
public BoardService(BoardDao boardDao) {
this.boardDao = boardDao;
}
3) Setter 주입 (선택적 주입에 유용)
private BoardDao boardDao;
@Autowired
public void setBoardDao(BoardDao boardDao) {
this.boardDao = boardDao;
}
[IoC & DI의 관계]
- IoC = 제어권을 컨테이너가 가짐
- DI = IoC를 실현하는 구체적인 방법(주입 방식)
- 즉, IoC 개념 위에서 DI가 동작하는 것!
[IoC/DI 장점 정리]
- 객체 관리의 일관성
- 객체 간 결합도 감소
- 테스트 용이성 (Mocking 가능)
- 유지보수 용이 (구현체 교체 시 코드 수정 ↓)
- 스프링이 모든 Bean을 싱글톤 패턴 기반으로 관리 (필요 시 prototype 등 스코프 변경 가능)
시각화 다이어그램
[ Spring Container (IoC) ]
┌───────────────────────────┐
| ┌──────────────┐ |
| | BoardDao | <──┐ |
| └──────────────┘ | |
| ┌──────────────┐ | |
| | BoardService |────┘ | (DI : 의존성 주입)
| └──────────────┘ |
| ┌──────────────┐ |
| | BoardController |
| └──────────────┘ |
└───────────────────────────┘