간단한 설명
Spring Bean 은 다음과 같은 생명 주기를 갖습니다.
스프링 컨테이너 생성 => 스프링 밴 생성 => 의존관계 주입( DI ) => 초기화 콜백 => 사용 => 소멸전 콜백 => 스프링 종료
위 생명 주기를 보면 스프링 빈은 객체를 생성하고, 의존관계 주입이 다 끝난 후에야 필요한 데이터를 사용할 수 있는 준비가 완료됩니다.
즉, 생성자가 호출되었을 때 스프링 빈은 초기화 전이고 DI 가 이루어지고 나서야 스프링 빈이 초기화 됩니다.
초기화 작업은 의존관계 주입이 모두 완료되고 난 다음에 호출하게 되는데, 개발자가 의존관계 주입이 완료된 시점이 언제인지 알 수 있는 방법이 없습니다.
그래서 Spring 은 다음과 같은 빈 생명주기 콜백을 지원합니다.
1. 인터페이스( InitializingBean, DisposableBean )
2. Bean 설정 정보에 초기화 메서드, 종료 메서드 지정
3. @PostConstruct, @PreDestroy 어노테이션
하지만 1번의 경우에는 거의 사용하지 않고 2, 3번이 많이 사용됩니다.
@PostConstruct, @PreDestroy
위 두 어노테이션은 최근 스프링에서 가장 권장하는 방법으로 어노테이션을 붙이기만 하면 되므로 매우 편리합니다.
패키지는 javax.annotation 으로 스프링에 종속적인 기술이 아닌 자바표준이기 때문에 스프링이 아닌 다른 컨테이너에서도 동작합니다.
@PostConstruct
생성자가 호출되었을 때, 의존관계주입이 끝나지 않았기 때문에 스프링 빈은 초기화 되지 않습니다.
하지만 @PostConstruct 를 이용해 의존 관계 주입(DI) 가 이루어진 후 초기화를 수행하여 객체의 값을 설정한 채로 호출할 수 있습니다.
@PreDestroy
ApplicationContext 에서 Bean 을 제거하기 위해 사용됩니다.
예시
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Component
public class ConnectTest {
private String message;
public ConnectTest() {
System.out.println("생성자 호출, message = " + message);
}
@PostConstruct
public void init() {
System.out.println("초기화 콜백");
connect();
}
@PreDestroy
public void close() {
System.out.println("종료 전 콜백");
disconnect();
}
public void connect() {
System.out.println("연결 완료 - message : " + message);
}
public void disconnect() {
System.out.println("연결 종료");
}
public void setMessage(String message) {
this.message = message;
}
}

@PostConstruct, @PreDestroy 의 단점
위 두 어노테이션의 단점은 외부 라이브러리에 적용하지 못한다는 점입니다.
외부 라이브러리를 초기화, 종료해야 한다면 @Bean 에 옵션을 추가하는 기능을 사용해야 합니다.
@Bean 옵션 초기화 메서드, 종료 메서드
설정 정보(Configuration) 아래와 같이 @Bean 어노테이션에 초기화, 종료 메서드를 지정하는 방식입니다.
@Configuration
static class ConnectConfig {
@Bean(initMethod = "init", destroyMethod = "close")
public ConnectTest connectTest() {
ConnectTest connectTest = new ConnectTest();
connectTest.setMessage("connect to http://localhost:8080");
return connectTest;
}
}
package com.example.spring2.lifecycle;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
public class ConnectTest {
private String message;
public ConnectTest() {
System.out.println("생성자 호출, message = " + message);
}
public void init() {
System.out.println("초기화 콜백");
connect();
}
public void close() {
System.out.println("종료 전 콜백");
disconnect();
}
public void connect() {
System.out.println("연결 완료 - message : " + message);
}
public void disconnect() {
System.out.println("연결 종료");
}
public void setMessage(String message) {
this.message = message;
}
}

'Spring' 카테고리의 다른 글
| 트랜잭션 프록시와 예외 (0) | 2025.04.08 |
|---|---|
| @Transactional , Spring Data JPA 을 같이 쓰는 점에 관하여 (0) | 2025.04.08 |
| 스프링의 메세지, 국제화 (0) | 2025.02.13 |
| @valid vs @validated (0) | 2025.02.03 |
| @Scheduled (0) | 2025.01.24 |