1. 목적
이 문서는 스프링 컨테이너가 Bean을 등록/생성/초기화/소멸시키는 라이프사이클을 정리하고, 그 과정에서 @PostConstruct가 어떤 의미와 위치를 가지는지 설명한다.
2. Bean이란
Bean은 스프링 컨테이너(ApplicationContext)가 생성 및 관리하는 객체이다.
컨테이너는 Bean의 라이프사이클을 관리하며, DI(의존성 주입)와 AOP 같은 부가 기능을 적용할 수 있게 한다.
3. “Bean 등록”과 “Bean 인스턴스 생성”의 차이
3.1 Bean 등록(정의 등록)
- 스프링은 애플리케이션 시작 시점에 빈 후보를 스캔하고, “이 클래스를 빈으로 관리한다”는 정의(BeanDefinition)를 컨테이너에 등록한다.
- 이 단계에서는 실제 객체 인스턴스가 만들어지지 않는다.
대표적인 등록 경로
@ComponentScan 기반의 @Component, @Service, @Repository, @Controller
@Configuration 내 @Bean 메서드
- XML 설정
3.2 Bean 인스턴스 생성(실제 객체 생성)
- 등록된 BeanDefinition을 바탕으로 실제 객체를 생성하고 의존성을 주입하고 초기화한다.
- 기본 싱글톤은 컨테이너 초기화 과정에서 미리 생성되는 경우가 많다(지연 로딩 설정에 따라 달라짐).
4. Bean 생성/초기화 흐름(대표적인 싱글톤 기준)
아래는 스프링의 일반적인 흐름을 이해하기 위한 “대표적인 순서”이다.
4.1 인스턴스 생성(instantiate)
- 생성자 호출 또는 팩토리 메서드 호출로 객체 인스턴스를 만든다.
4.2 의존성 주입(populate properties)
@Autowired, @Value, 세터 주입 등을 적용하여 의존성을 주입한다.
- 생성자 주입은 4.1 단계에서 이미 주입이 완료된다.
- 필드/세터 주입은 4.2 단계에서 완료된다.
4.3 Aware 콜백(선택)
BeanNameAware, ApplicationContextAware 등을 구현한 경우, 컨테이너 관련 정보를 주입한다.
4.4 BeanPostProcessor 전처리(초기화 이전)
- 스프링은 Bean 생성 과정에서 전/후 처리기를 실행한다.
- 일부 AOP 프록시 준비 과정이 포함될 수 있다.
4.5 초기화(initialize)
- 이 단계에서 초기화 콜백이 실행된다.
- 실행 가능한 초기화 훅(대표)
@PostConstruct
InitializingBean#afterPropertiesSet()
@Bean(initMethod = "init")
4.6 BeanPostProcessor 후처리(초기화 이후)
- 필요 시 프록시가 최종 적용/교체될 수 있다.
4.7 사용 가능 상태
- 싱글톤 캐시에 등록되어 DI 대상으로 제공되며 사용 가능한 상태가 된다.
5. @PostConstruct 정리
5.1 정의
@PostConstruct는 “의존성 주입이 완료된 직후” 한 번 실행되는 초기화 메서드를 지정하는 애노테이션이다.
5.2 위치
Bean 라이프사이클 기준으로
- 인스턴스 생성 이후
- 의존성 주입 이후
- 초기화 단계에서 실행된다
5.3 사용 목적
주입된 의존성/설정값을 기반으로 “빈을 사용 가능한 상태로 만들기 위한 준비”를 수행한다.
권장되는 사용 예
- 설정 검증(필수 값 누락 시 빠른 실패)
- 내부 캐시/매핑 테이블 구성
- 정규식/포맷터/파서 등의 준비(외부 의존이 없는 작업)
비권장되는 사용 예
- 대량 DB 조회, 외부 API 호출 등 무거운 작업(기동 지연/장애 전파)
- 전체 싱글톤 생성 완료 이후를 전제로 하는 로직(순서 의존)
6. @PostConstruct를 대체/보완하는 방법
6.1 생성자 주입 + 불변 설계
- 가능한 경우 초기화 단계를 줄이기 위해 생성자에서 필수 구성 요소를 완성하고 불변 객체로 유지한다.
6.2 initMethod / InitializingBean
@Bean(initMethod = "init")
InitializingBean#afterPropertiesSet()
- 둘 다 “초기화 단계”에 실행되며 역할은 유사하다.
6.3 전체 싱글톤 준비 완료 후 실행이 필요하면
SmartInitializingSingleton을 사용한다.
- 모든 싱글톤 빈이 생성된 뒤 한 번 호출되는 훅이므로 초기화 순서 의존 문제에 더 안전하다.
6.4 애플리케이션 완전 기동 후 실행이 필요하면(Spring Boot)
ApplicationReadyEvent 등 이벤트 기반 훅을 고려한다.
- 외부 연동/워밍업 같은 작업은 이 방식이 더 안전한 경우가 많다.