반응형
- 일반적인 자바 개발의 경우 객체를 사용하기 위해 다음과 같은 코드를 사용함
public interface MyService {
public String getHello();
}
@Service
public class MyServiceImpl implements MyService {
@Override
public String getHello() {
return "Hello";
}
}
@RestController
public class NoDIController {
private MyService service = new MyServiceImpl(); // 직접 생성
@GetMapping("/no-di/hello")
public String getHello() {
return service.getHello();
}
}
다이어그램을 그려보면
1. 일반적인 자바 개발 경우
- MyServiceImpI을 직접 new로 생성해서 MyService에 저장
- 개발자가 객체 생성 제어권을 갖고 있는 방식
또 다른 예제
Engine engine = new DieselEngine(); // 내가 직접 만든다
Car car = new Car(engine);
car.drive();
- 자동차를 만들 때, 엔진을 내가 직접 선택해서 new로 만든다
- 바꿀 일이 생기면 코드도 수정해야 한다
개발자가 모든 걸 직접 컨트롤
- 어떤 객체 쓸지 (new로 생성)
- 언제 만들지
- 어떤 구현체를 쓸지 (직접 결정)
2. IoC 방식
- 제어 역전의 특징을 가진 스프링은 기존 자바 개발 방식과 다르게 동작
- 사용할 객체를 직접 생성하지 않고 객체의 생명 주기 관리를 외부에 위임
- IoC == 객체의 생성과 생명 주기 제어를 개발자가 아니라 외부(컨테이너가) 담당
예제
- Engine을 new 하지 않음!
- Spring이 알아서 Engine을 만들어서 Car에 "끼워줌"
@RequiredArgsConstructor
public class Car {
private final Engine engine; // 주입받음 (DI)
public void drive() {
engine.run();
}
}
Spring IoC 컨테이너란?
- 객체를 대신 만들어주고, 필요한 곳에 주입해주고, 생명 주기를 관리해주는 핵심 컴포넌트
- 대표적으로는 ApplicationContext
Spring IoC 컨테이너 동작 흐름
예제 코드
public interface MyService {
String getHello();
}
@Service
public class MyServiceImpl implements MyService {
public String getHello() {
return "Hello from MyServiceImpl";
}
}
@RestController
@RequiredArgsConstructor
public class MyController {
private final MyService service;
@GetMapping("/di/hello")
public String getHello() {
return service.getHello();
}
}
1단계 : 설정 파일/어노테이션 읽기(클래스 스캔)
- Spring이 시작될 때 @ComponentScan이 설정된 패키지를 스캔함
- @Service가 붙은 MyServiceImpl 발견 → Bean으로 등록
- @RestController가 붙은 MyController도 발견 → Bean으로 등록
2단계 : Bean 정의(설계도)를 만들어 저장
- Spring은 어떤 클래스인지, 어떤 생성자를 써야 하는지, 어떤 의존성이 필요한지를 메모리에 미리 등록
Bean 이름 타입 생성 방법 의존성
myServiceImpl | MyService | new MyServiceImpl() | 없음 |
myController | MyController | new MyController(myService) | MyService 필요함 |
💡 Bean이란?
Spring IoC 컨테이너가 생성하고 관리하는 객체(인스턴스)
3단계. Bean 인스턴스를 생성
- 필요한 Bean들을 실제로 생성(new) 하고
- 생성 시점에 필요한 의존성(=다른 객체)도 같이 만들어서 주입
- 먼저 MyServiceImpl을 생성하고, 그다음 MyController를 생성할 때 MyServiceImpl을 자동으로 넣어줌
이 부분 의존성 주입
MyService myService = new MyService(); // spring이 생성
MyController controller = new MyController(myService); // spring이 주입
4단계. 싱글톤으로 관리
- 대부분의 Bean은 하나만 만들어서 공유(Singleton)
- 필요할 때마다 계속 new 하는 게 아니라, 만들어둔 거에서 꺼내서 씀 → 메모리에 보관
5단계. 요청 처리 중 주입된 Bean 사용
- 사용자가 /di/hello로 요청을 보냄
- Spring MVC가 MyController.getHello() 메서드 실행
- 내부에서 주입된 MyServiceImpl의 getHello() 호출됨
- 응답으로 "Hello from MyServiceImpl" 반환
@GetMapping("/di/hello")
public String getHello() {
return service.getHello();
}
정리
반응형
'Spring Boot > 제어 역전(loC), 의존성 주입(DI)' 카테고리의 다른 글
[Spring boot] 의존성 주입(DI) (0) | 2025.07.21 |
---|