Spring
Spring Bean 라이프사이클에 대해서 설명해주세요
생성부터 소멸까지 14단계 흐름, @PostConstruct·@PreDestroy, BeanPostProcessor의 AOP 프록시 생성까지. 면접에서 자주 묻는 Bean 라이프사이클을 인터랙티브 시각화로 완벽히 준비합니다.
2026년 3월 15일 · 약 10분 읽기
Q. "Spring IoC 컨테이너가 Bean을 어떻게 생성하고 초기화하며 소멸시키는지 설명해주세요."
예상 꼬리질문
답변 가이드
"Spring Bean은 인스턴스화 → 의존성 주입 → 초기화 콜백 → 사용 → 소멸 콜백의 라이프사이클을 거칩니다. IoC 컨테이너가 단순히 new로 만드는 것이 아니라 정교하게 관리합니다."
"초기화 콜백은 @PostConstruct → afterPropertiesSet() → initMethod 순서로 실행됩니다. @PostConstruct가 JSR-250 표준이라 Spring에 의존하지 않아 가장 권장됩니다."
"BeanPostProcessor는 모든 Bean의 초기화 전후에 실행되는 확장 포인트입니다. Spring의 @Transactional, @Cacheable이 이 메커니즘으로 초기화 후 Bean 객체를 프록시 객체로 교체합니다."
@PostConstruct가 없었다면 DB 커넥션 풀은 언제 초기화해야 할까요? 생성자에서 @Autowired 필드를 쓰면 왜 NullPointerException이 날까요?
이 아티클에서는 Bean 라이프사이클 14단계 흐름부터 초기화 콜백 비교, BeanPostProcessor의 AOP 프록시 생성까지 직접 체험하며 이해합니다.
1. Bean 라이프사이클 전체 흐름
꼬리질문: "Spring Bean의 라이프사이클 단계를 순서대로 설명해주세요"
Spring IoC 컨테이너는 Bean을 단순히 new로 만들지 않습니다. 인스턴스화 → 의존성 주입 → Aware 인터페이스 → BeanPostProcessor(전) → 초기화 콜백 → BeanPostProcessor(후) → 사용 → 소멸 콜백 순서로 정교하게 관리합니다.
각 단계를 순서대로 진행되기 때문에, 어느 시점에 어떤 콜백이 실행되는지 파악하면 초기화 버그 대부분을 예방할 수 있습니다.
단계를 클릭하며 각 시점에 무슨 일이 일어나는지 확인해 보세요.
인스턴스화
Spring 컨테이너가 Bean 클래스의 생성자를 호출해 객체를 생성합니다. 이 시점에는 의존성이 아직 주입되지 않았습니다.
MyBean bean = new MyBean(); // 생성자 호출
2. 초기화 콜백 3가지 비교
꼬리질문: "@PostConstruct, InitializingBean, initMethod의 차이와 실행 순서는?"
초기화 콜백은 세 가지 방법으로 등록할 수 있습니다. @PostConstruct는 JSR-250 표준이라 Spring에 의존하지 않아 권장됩니다. InitializingBean은 Spring 인터페이스 구현이 필요해 결합도가 높습니다. @Bean(initMethod)는 소스 수정이 불가능한 외부 라이브러리 Bean에 유용합니다.
세 방법이 모두 존재할 때 실행 순서는 @PostConstruct → afterPropertiesSet() → initMethod 입니다.
세 방식을 나란히 비교해 보세요.
JSR-250 표준 어노테이션으로 Spring에 의존하지 않습니다. 의존성 주입이 완료된 이후 실행이 보장됩니다.
@Component
public class DatabasePool {
@Autowired
private DataSource dataSource;
@PostConstruct
public void init() {
// 의존성 주입 완료 후 실행
pool = new HikariPool(dataSource);
log.info("Pool 초기화 완료");
}
}- ✓JSR-250 표준 (Spring 비의존)
- ✓코드가 간결하고 직관적
- ✓테스트 코드에서 직접 호출 가능
3. @PostConstruct가 필요한 이유
꼬리질문: "생성자에서 @Autowired 필드를 쓰면 왜 NPE가 발생하나요?"
생성자에서 @Autowired 필드를 사용하면 NullPointerException이 발생합니다. 필드 주입은 생성자 실행 이후에 이루어지기 때문입니다. @PostConstruct는 의존성 주입이 완료된 이후에 호출되므로 모든 필드가 안전하게 초기화된 상태에서 로직을 실행할 수 있습니다.
더 나은 패턴은 생성자 주입을 사용하는 것입니다. Spring이 생성자 호출 시점에 의존성을 함께 전달하므로, 생성자 내부에서 바로 의존 객체를 사용할 수 있습니다.
주입 방식별로 어느 시점에 필드가 초기화되는지 비교해 보세요.
@Component
class UserService {
@Autowired
private UserRepository repo; // 필드 주입
public UserService() {
// repo = null! 위험
}
@PostConstruct
public void init() {
// repo 안전하게 사용 가능
repo.findAll();
}
}@Component
class UserService {
private final UserRepository repo;
// Spring이 생성자 호출 시
// 의존성 함께 전달
public UserService(
UserRepository repo) {
this.repo = repo;
repo.findAll(); // 즉시 안전!
}
}4. BeanPostProcessor — 모든 Bean에 공통 로직 적용
꼬리질문: "BeanPostProcessor가 무엇이고 어떻게 AOP 프록시를 만드나요?"
BeanPostProcessor는 컨테이너에 등록된 모든 Bean의 초기화 전/후에 실행되는 확장 포인트입니다. postProcessAfterInitialization()에서 Bean 객체를 프록시 객체로 교체할 수 있습니다.
Spring의 @Transactional, @Cacheable, @Async가 모두 이 방식으로 프록시를 생성합니다. 즉 AOP의 동작 기반이 BeanPostProcessor입니다.
BeanPostProcessor가 Bean을 프록시로 교체하는 과정을 직접 확인해 보세요.
면접 체크리스트
이 항목들을 자신 있게 설명할 수 있다면 Bean 라이프사이클 질문은 준비 완료입니다.
- - 라이프사이클 순서: 인스턴스화 → 의존성 주입 → Aware → BPP(전) → 초기화 → BPP(후) → 사용 → 소멸
- - @PostConstruct: 의존성 주입 완료 후 초기화 — DB 커넥션 풀, 캐시 로딩에 사용
- - 초기화 콜백 순서: @PostConstruct → afterPropertiesSet() → initMethod
- - @PreDestroy: 컨테이너 종료 전 정리 — Thread Pool, 외부 연결 해제
- - BeanPostProcessor: 모든 Bean에 공통 처리 — AOP 프록시 생성의 핵심 메커니즘
- - prototype 스코프: 소멸 콜백 미호출 — 직접 자원 해제 필요
참고 자료
- 기억보단 기록을 — Spring Bean 라이프사이클 정리 — Bean 라이프사이클을 코드와 그림으로 친절하게 설명하는 국내 블로그
- Baeldung — Spring Bean Lifecycle — 각 콜백 방법의 실행 순서를 예제 코드와 함께 명확히 설명하는 영문 튜토리얼
의견을 들려주세요
서비스 개선에 큰 도움이 됩니다. 익명으로 자유롭게 남겨주세요.