명시적 DI가 어떻게 동작하는지 단계별로 쪼개서 설명
1. Maven 의존성 추가
- spring-context 하나만 넣으면,
- IoC 컨테이너(Core BeanFactory)
- 애노테이션 지원
- JavaConfig (@Configuration/@Bean)
- AOP, 이벤트, 리소스 처리 등 핵심 모듈이 전부 따라온다.
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.2.2</version>
</dependency>
- 이 한 줄로 스프링 컨테이너가 제공하는 모든 기능을 쓸 준비가 된다.
2. 설정 클래스(@Configuration) 작성
- @Configuration:
- ‘이 클래스는 빈 설정 정보를 담은 파일입니다’라고 표시한다.
- 스프링이 이 클래스를 읽어서 내부적으로 CGLIB 프록시 클래스로 감싼다.
- 그래서 @Bean 메서드를 여러 번 호출해도 항상 싱글톤 빈을 반환할 수 있다.
- 예시
@Configuration
public class WasherConfig {
// 아래 @Bean 메서드들이 이 컨테이너에 등록될 메타정보를 만든다.
}
3. @Bean 메서드로 메타정보 작성
- 각 @Bean 메서드는 메타데이터(BeanDefinition) 하나를 만든다.
- 이름: 메서드 이름 그대로 (sWasher, lWasher, washerUser)
- 타입: 메서드 반환 타입 (Washer, LWasher, WasherUser)
- 의존관계: 메서드 내부에서 호출한 다른 @Bean(예: sWasher()) → 주입 대상 표시
- 구체 예시
@Configuration
public class WasherConfig {
// 기본 세탁기 빈 등록 (이름 = "sWasher")
@Bean
public Washer sWasher() {
Washer w = new Washer();
w.setMode("표준");
return w;
}
// 고급 세탁기 빈 등록 (이름 = "lWasher")
@Bean
public LWasher lWasher() {
LWasher w = new LWasher();
w.setMode("울코스");
return w;
}
// 사용자 빈 등록 (이름 = "washerUser")
@Bean(name = "myUser")
public WasherUser washerUser() {
WasherUser user = new WasherUser();
// 의존성 주입: sWasher 빈을 setter로 연결
user.setWasher(sWasher());
return user;
}
}
- 한 줄씩 요약
- @Bean public Washer sWasher() → “빈 이름 ‘sWasher’, 타입 Washer, 생성 로직은 new Washer()”
- user.setWasher(sWasher()) → “washerUser 빈이 sWasher 빈을 필요로 한다”
4. 스프링 컨테이너 구동 & 빈 생성 흐름
ApplicationContext ctx =
new AnnotationConfigApplicationContext(WasherConfig.class);
- 컨테이너 생성
- WasherConfig 클래스 로딩
- @Bean 메서드마다 BeanDefinition 등록
- 빈 생성 시점에 따라 아래 단계로 진행
- 빈 생성 순서 (간략화)
- 인스턴스화: new Washer() 등 호출
- 의존관계 주입: setter 주입, 생성자 인자 주입 등
- 초기화 콜백: @PostConstruct나 InitializingBean 실행
- 싱글톤 레지스트리 등록: 컨테이너 내부 맵에 저장
- 이 과정을 컨테이너가 전부 관리하고, 개발자는 설정 선언만 했다.
5. 빈 조회(getBean)
- 타입 단독 조회
Washer w = ctx.getBean(Washer.class);
- 빈이 하나일 때 편리하게 쓴다.
- 같은 타입 빈이 둘 이상이면 예외(NoUniqueBeanDefinitionException) 발생.
- 이름 + 타입 조회
- 빈 이름(@Bean(name="myUser"))을 지정해서 정확히 꺼낸다.
WasherUser user = ctx.getBean("myUser", WasherUser.class);
- 필요하면 alias도 사용 가능→ 두 개의 이름으로 동일 빈 조회 가능
@Bean({"mainUser","primaryUser"})
public WasherUser washerUser() { … }
추가 팁
- @Configuration 프록시
- @Configuration 클래스는 CGLIB로 프록시 처리되어
- sWasher() 호출 시 매번 새 객체가 아니라,
- 컨테이너가 관리하는 싱글톤 인스턴스를 리턴하게 된다.
- 메타데이터 확장
- @Conditional, @Profile 같은 애노테이션으로
- “특정 조건일 때만 빈을 등록” 같은 고급 설정도 가능하다.
이렇게 명시적으로 “이것이 빈이다!” 를 하나하나 선언하는 방식이 바로 명시적 DI다
'SpringBoot' 카테고리의 다른 글
DI(Dependency Injection) - (3) (0) | 2025.04.18 |
---|---|
DI(Dependency Injection) - (1) (1) | 2025.04.18 |
Spring Framework (1) | 2025.04.16 |
세션과 JWT의 차이 (0) | 2025.01.12 |
SpringBoot 잡동사니 (0) | 2025.01.12 |