1. 스프링 컨테이너 생성
1-1. 스프링 컨테이너란?
스프링 컨테이너는 ApplicationContext를 말한다.
ApplicationContext는 인터페이스이며 스프링 빈들을 관리하고 조회하는 역할을 담당한다.
ApplicationContext applicationContext =
new AnnotationConfigApplicationContext(AppConfig.class);
1-2. 컨테이너 생성 과정
1단계: 스프링 컨테이너 생성
- new AnnotationConfigApplicationContext(AppConfig.class)로 생성
- 구성 정보(AppConfig.class)를 지정해야 함
2단계: 스프링 빈 등록
- 설정 클래스의 @Bean 메서드를 읽어 빈을 등록
- 빈 이름은 기본적으로 메서드 이름 사용
- @Bean(name="customName")으로 직접 지정 가능
- 빈 이름은 항상 다르게 부여해야 함
3단계: 의존관계 주입
- 설정 정보를 참고해서 의존관계를 주입(DI)
- 자바 코드로 빈을 등록하면 생성자 호출하면서 의존관계 주입도 한번에 처리됨
2. 스프링 빈 조회
2-1. 기본 조회 방법
// 빈 이름으로 조회
ac.getBean("memberService", MemberService.class)
// 타입으로 조회
ac.getBean(MemberService.class)
// 빈이 없으면 NoSuchBeanDefinitionException 발생
2-2. 동일한 타입이 둘 이상일 때
타입으로 조회 시 같은 타입의 빈이 여러 개 있으면 NoUniqueBeanDefinitionException 발생
- 빈 이름을 지정해서 조회
- ac.getBeansOfType()으로 해당 타입의 모든 빈 조회
2-3. 상속 관계 조회
부모 타입으로 조회하면 자식 타입도 함께 조회된다.
- Object 타입으로 조회하면 모든 스프링 빈 조회 가능
3. BeanFactory와 ApplicationContext
스프링 컨테이너의 구조를 이해하기 위해서는 BeanFactory와 ApplicationContext의 관계를 알아야 한다.
BeanFactory는 스프링 컨테이너의 최상위 인터페이스로, 스프링 빈을 관리하고 조회하는 가장 기본적인 기능을 제공한다. 우리가 지금까지 사용했던 getBean() 메서드가 바로 BeanFactory에서 제공하는 대표적인 기능이다.
그런데 실제 애플리케이션 개발에서는 빈을 관리하고 조회하는 것만으로는 부족하다. 국제화 처리, 환경 변수 관리, 애플리케이션 이벤트 발행 등 다양한 부가 기능이 필요하다. 이러한 필요성 때문에 ApplicationContext가 등장했다.
ApplicationContext는 BeanFactory를 상속받아 빈 관리 기능은 물론이고, 실무에서 필요한 여러 부가 기능을 추가로 제공한다. 구체적으로 MessageSource 인터페이스를 통해 메시지 국제화 기능을, EnvironmentCapable 인터페이스를 통해 로컬/개발/운영 환경을 구분하는 기능을, ApplicationEventPublisher 인터페이스를 통해 이벤트 발행과 구독 기능을, ResourceLoader 인터페이스를 통해 파일이나 클래스패스 등의 리소스를 편리하게 조회하는 기능을 제공한다.
결국 BeanFactory는 스프링 컨테이너의 핵심 기능만 제공하는 가장 단순한 형태이고, ApplicationContext는 여기에 실무에 필요한 다양한 부가 기능을 더한 확장된 버전이라고 이해하면 된다.
실무에서는 BeanFactory를 직접 사용할 일이 거의 없고, 대부분 ApplicationContext를 스프링 컨테이너로 사용한다.
3-1. 빈 등록과 저장 방식
스프링 컨테이너에 빈이 등록되면 내부적으로 어떻게 저장될까? 스프링 컨테이너는 빈을 관리하기 위해 내부에 빈 저장소를 가지고 있다.
이 저장소는 기본적으로 Map 구조로 되어 있으며, 키(Key)는 빈 이름(String), 값(Value)은 실제 빈 객체(Object)로 저장된다.
예를 들어 @Bean 메서드로 memberService를 등록하면, 스프링 컨테이너 내부의 Map에 "memberService" 라는 이름을 키로, 실제 생성된 MemberServiceImpl 인스턴스를 값으로 저장한다. 이렇게 Map 구조로 관리하기 때문에 빈 이름으로 빠르게 조회할 수 있고, 같은 이름의 빈을 중복 등록할 수 없다.
또한 스프링 컨테이너는 각 빈에 대한 메타정보인 BeanDefinition도 함께 관리한다. BeanDefinition에는 빈의 클래스 정보, 스코프, 생성자 파라미터, 초기화 메서드, 소멸 메서드 등의 정보가 담겨 있다. 빈을 실제로 생성하고 관리할 때 이 메타정보를 참조한다.
빈의 생명주기 관리 측면에서 보면, 스프링 컨테이너가 시작될 때 설정 정보를 읽어 BeanDefinition을 생성하고, 이를 기반으로 빈 인스턴스를 생성해서 컨테이너 내부 저장소에 보관한다. 기본적으로 싱글톤 스코프이기 때문에 애플리케이션 전체에서 하나의 인스턴스만 생성되어 공유된다.
이후 getBean() 메서드로 빈을 조회하면, 컨테이너는 내부 Map에서 해당 이름의 빈을 찾아 반환하는 방식으로 동작한다.
4. 다양한 설정 형식
4-1. 자바 코드 기반 설정 (권장)
new AnnotationConfigApplicationContext(AppConfig.class)
4-2. XML 기반 설정 (레거시)
new GenericXmlApplicationContext("appConfig.xml")
<bean id="memberService" class="hello.core.member.MemberServiceImpl">
<constructor-arg name="memberRepository" ref="memberRepository" />
</bean>
5. BeanDefinition - 설정 메타정보
5-1. BeanDefinition이란?
스프링이 다양한 설정 형식을 지원할 수 있는 비결은 BeanDefinition이라는 추상화 덕분이다.
- XML이든 자바 코드든 BeanDefinition만 생성하면 됨
- 스프링 컨테이너는 BeanDefinition만 알면 됨
- @Bean, <bean> 당 각각 하나씩 메타정보 생성
5-2. 주요 메타정보
- BeanClassName: 생성할 빈의 클래스명
- factoryBeanName: 팩토리 빈 이름 (ex: appConfig)
- factoryMethodName: 빈 생성 팩토리 메서드 (ex: memberService)
- Scope: 싱글톤(기본값)
- lazyInit: 지연 로딩 여부
- InitMethodName: 초기화 메서드명
- DestroyMethodName: 소멸 메서드명
결론
- ApplicationContext를 스프링 컨테이너라고 한다
- 스프링 컨테이너는 설정 정보를 참고해서 빈을 등록하고 의존관계를 설정한다
- 빈은 내부적으로 Map 구조(빈 이름 → 빈 객체)로 저장되며, BeanDefinition 메타정보와 함께 관리된다
- 다양한 형식의 설정 정보를 BeanDefinition으로 추상화해서 사용한다
- BeanFactory보다 ApplicationContext를 사용하는 것이 일반적이다
- 실무에서는 BeanDefinition을 직접 다룰 일은 거의 없다
'공부일기.. > Spring' 카테고리의 다른 글
| [spring] @Component vs @Configuration 차이점 (0) | 2025.10.24 |
|---|---|
| [spring] final 키워드와 @RequiredArgsConstructor의 원리 (0) | 2025.10.22 |
| [spring] 언제! 리팩토링해야 할까? 실전 가이드-유지보수성 문제 (파트 3/3) (0) | 2025.10.05 |
| [spring] 언제! 리팩토링해야 할까? 실전 가이드- 코드 품질 문제 (2/3) (0) | 2025.10.04 |
| [spring] 언제! 리팩토링해야 할까? 실전 가이드- 설계원칙 위반 (1/3) (0) | 2025.10.03 |