1. 빈 생명주기 콜백의 필요성
- 콜백이란? 특정 이벤트 발생 시 프레임워크가 개발자가 등록한 메서드를 자동으로 호출하는 개념
- 스프링 컨테이너는 빈의 객체 생성 → 의존관계 주입 → 초기화 → 소멸이라는 라이프사이클을 관리
- 애플리케이션 시작 시 필요한 작업(DB 연결, 네트워크 소켓 연결 등..)이나 종료 전 리소스 정리 작업을 수행하기 위해 콜백 필요
- 개발자는 빈이 생성되고 의존성이 주입된 시점, 그리고 빈이 소멸되기 직전 시점에 특정 로직을 실행할 수 있음
2. 객체 생성과 의존관계 주입
2.1 객체 생성 및 의존관계 주입 방법
- 생성자 주입: 객체의 생성과 의존관계 주입이 동시에 일어남
- Setter 주입: 기본 생성자로 객체 생성 후 Setter 메서드 호출하여 의존성 주입
- Field 주입: DI 컨테이너가 리플렉션을 사용하여 필드에 직접 접근해 주입
2.2 생성자 주입이 동시에 일어나는 이유
- 동작 방식: 생성자 주입은 객체가 생성될 때 매개변수로 필요한 모든 의존성을 전달받음
- 강제성: 필수 의존성이 없으면 객체 생성 자체가 불가능 (모든 의존성이 준비되어야 빈 생성 가능)
- 불변성: 생성 후에 의존관계를 변경할 수 없음 (final 키워드 사용 가능)
- 안정성 향상:
- NullPointerException 방지 (의존성이 항상 보장됨)
- 의존관계가 부족하면 컴파일 타임에 오류 발생 → 디버깅이 용이
- 순환 참조를 컴파일 타임에 탐지 가능
3. 스프링 빈 라이프사이클 전체 흐름
스프링 IoC 컨테이너 생성 → 스프링 빈 생성 → 의존관계 주입 → 초기화 콜백 메서드 호출 → 사용 → 소멸 전 콜백 메서드 호출 → 스프링 종료
3.1 단계별 상세 설명
- 스프링 IoC 컨테이너 생성: ApplicationContext 구현체 생성
- 스프링 빈 생성: 빈 등록 정보에 따라 객체 생성
- 의존관계 주입: 선택한 주입 방식(생성자, Setter, Field)에 따라 의존성 주입
- 초기화 콜백: 빈이 준비되었을 때 호출되는 메서드 실행
- 사용: 애플리케이션에서 빈 사용
- 소멸 전 콜백: 빈이 소멸되기 직전에 호출되는 메서드 실행
- 스프링 종료: 컨테이너 종료 및 모든 빈 소멸
3.2 빈 초기화와 소멸 시점의 중요성
- 초기화: 빈이 생성되고 의존성이 모두 주입된 후 실제 사용에 앞서 필요한 추가 설정 작업 수행
- 소멸: 애플리케이션 종료 시 리소스 해제, 연결 종료 등 정리 작업 수행
4. 빈 생명주기 콜백 구현 방법 (3가지)
4.1 인터페이스 방식
- InitializingBean:
afterPropertiesSet() 메서드 구현 (초기화)
- DisposableBean:
destroy() 메서드 구현 (소멸)
- 특징:
- 스프링 프레임워크에 의존적인 코드가 됨
- 메서드명을 변경할 수 없음
- 외부 라이브러리에 적용할 수 없음
public class MyBean implements InitializingBean, DisposableBean {
@Override
public void afterPropertiesSet() throws Exception {
}
@Override
public void destroy() throws Exception {
}
}
4.2 설정 정보를 통한 방식
- @Bean 어노테이션 속성으로 초기화, 소멸 메서드 지정
- 특징:
- 메서드명을 자유롭게 지정 가능
- 스프링 코드에 의존하지 않음
- 외부 라이브러리에도 적용 가능
@Configuration
public class AppConfig {
@Bean(initMethod = "init", destroyMethod = "close")
public MyBean myBean() {
return new MyBean();
}
}
- destroyMethod 속성의 추론 기능:
close, shutdown과 같은 이름의 메서드가 있으면 자동으로 호출
- 추론 기능을 사용하지 않으려면
destroyMethod="" 지정
4.3 어노테이션 방식
- @PostConstruct: 초기화 메서드에 지정
- @PreDestroy: 소멸 메서드에 지정
- 특징:
- 가장 권장되는 방식 (스프링에서 공식 권장)
- 스프링이 아닌 JSR-250 자바 표준으로, 다른 컨테이너에서도 동작
- 컴포넌트 스캔과 잘 어울림
- 외부 라이브러리에는 적용 불가 (코드를 수정할 수 없기 때문)
public class MyBean {
@PostConstruct
public void init() {
}
@PreDestroy
public void close() {
}
}
5. 빈 생명주기 콜백 방식 선택 추천
- 최우선:
@PostConstruct, @PreDestroy 어노테이션 (대부분의 경우)
- 차선책: 외부 라이브러리를 초기화/종료해야 하는 경우
@Bean의 initMethod, destroyMethod 속성 사용