포스트

Spring Bean Lifecycle 정리

왜 생명주기를 알아야 하는가

스프링 빈은 단순히 객체가 생성되고 끝나는 것이 아니다. 생성, 의존성 주입, 초기화, 사용, 소멸까지 컨테이너가 관리한다. 그래서 어느 시점에 어떤 코드가 실행되는지 알아야 다음 문제를 제대로 디버깅할 수 있다.

  • @PostConstruct가 왜 안 불리지?
  • AOP 프록시는 언제 감싸지지?
  • 초기화 시점에 다른 빈을 써도 안전한가?
  • 종료 훅은 어디에 두는가

전체 흐름

  1. 컨테이너 시작
  2. BeanDefinition 로딩
  3. 빈 인스턴스 생성
  4. 의존성 주입
  5. Aware 콜백
  6. BeanPostProcessor 적용
  7. 초기화 콜백
  8. 빈 사용
  9. 종료 시 소멸 콜백

1. 컨테이너 초기화

ApplicationContext가 생성되고 설정 정보가 읽힌다. 이 단계에서 어떤 빈들이 존재하는지에 대한 메타정보, 즉 BeanDefinition이 준비된다.

2. 빈 생성과 의존성 주입

이후 실제 객체가 생성되고 생성자 주입, 필드 주입, 세터 주입이 수행된다. 단일 생성자 주입이 가장 권장되는 이유도 이 단계가 가장 명확하게 드러나기 때문이다.

3. 초기화 콜백

초기화 시점에 쓰는 대표 수단은 다음과 같다.

  • @PostConstruct
  • InitializingBean#afterPropertiesSet
  • @Bean(initMethod = "...")

실무에서는 프레임워크 의존성이 덜한 @PostConstruct를 가장 자주 쓴다. 다만 초기화 시점에 너무 무거운 작업을 넣으면 애플리케이션 기동 시간이 길어진다.

4. BeanPostProcessor와 프록시

이 단계가 중요한 이유는 AOP, @Transactional, @Async 같은 기능이 빈 후처리 과정에서 프록시로 감싸질 수 있기 때문이다.

즉, 우리가 주입받는 객체가 항상 원본 클래스 그 자체는 아닐 수 있다.

5. 종료 시점

컨테이너가 내려갈 때는 @PreDestroy, DisposableBean, destroyMethod 등이 사용된다. 커넥션 정리, 외부 리소스 해제, 버퍼 flush 같은 작업이 이 구간에 들어간다.

실무에서 기억할 점

  • 초기화 로직은 짧고 명확해야 한다.
  • 다른 빈의 상태에 과하게 의존하는 초기화 코드는 위험하다.
  • 프록시가 개입하는 시점을 이해해야 @Transactional 동작을 해석할 수 있다.
  • 종료 콜백이 항상 호출된다고 낙관하면 안 된다. 강제 종료 상황도 있다.

정리

빈 생명주기를 이해하면 스프링이 “어떤 순서로 객체를 다루는지”가 보인다. 그 순간 초기화 시점, 프록시 적용, 트랜잭션 미적용, 종료 훅 누락 같은 문제들이 훨씬 쉽게 읽힌다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.

댓글

아직 댓글이 없습니다