Spring/이론
Spring Bean 생명주기 - 실무에서 알아야 할 핵심만
JuNo_12
2025. 6. 5. 10:01
초기화와 소멸 콜백 방법
Bean의 초기화와 소멸 시점에 특정 작업을 수행하는 3가지 방법을 알아보겠습니다.
1. @PostConstruct / @PreDestroy (권장)
@Service
public class FileService {
private FileWriter fileWriter;
@PostConstruct
public void init() {
try {
fileWriter = new FileWriter("application.log");
System.out.println("파일 연결 완료!");
} catch (IOException e) {
throw new RuntimeException("파일 초기화 실패", e);
}
}
@PreDestroy
public void cleanup() {
try {
if (fileWriter != null) {
fileWriter.close();
System.out.println("파일 연결 종료!");
}
} catch (IOException e) {
System.err.println("파일 정리 실패: " + e.getMessage());
}
}
}
2. @Bean의 initMethod/destroyMethod
외부 라이브러리나 @PostConstruct를 쓸 수 없는 경우에 사용합니다.
public class DatabaseConnection {
public void connect() {
System.out.println("데이터베이스 연결 시작");
}
public void disconnect() {
System.out.println("데이터베이스 연결 종료");
}
}
@Configuration
public class AppConfig {
@Bean(initMethod = "connect", destroyMethod = "disconnect")
public DatabaseConnection databaseConnection() {
return new DatabaseConnection();
}
}
3. InitializingBean / DisposableBean 인터페이스
잘 사용하지 않지만 알아두면 좋습니다.
@Service
public class CacheService implements InitializingBean, DisposableBean {
@Override
public void afterPropertiesSet() throws Exception {
// 초기화 로직
}
@Override
public void destroy() throws Exception {
// 정리 로직
}
}
실행 순서
여러 방법을 함께 사용할 경우의 실행 순서입니다.
초기화 순서:
- 생성자 → 의존성 주입 → @PostConstruct → InitializingBean → initMethod
소멸 순서:
- @PreDestroy → DisposableBean → destroyMethod
실무 활용 사례
캐시 워밍업
@Service
public class ProductService {
@Autowired
private ProductRepository productRepository;
private Map<Long, Product> productCache = new ConcurrentHashMap<>();
@PostConstruct
public void warmUpCache() {
List<Product> popularProducts = productRepository.findPopularProducts();
popularProducts.forEach(product ->
productCache.put(product.getId(), product)
);
System.out.println("캐시 워밍업 완료: " + productCache.size() + "개");
}
}
외부 API 연결 관리
@Service
public class PaymentService {
private PaymentApiClient apiClient;
@PostConstruct
public void initializeApiClient() {
apiClient = PaymentApiClient.builder()
.apiKey("your-api-key")
.timeout(Duration.ofSeconds(30))
.build();
if (!apiClient.isHealthy()) {
throw new RuntimeException("결제 API 연결 실패");
}
}
@PreDestroy
public void closeApiClient() {
if (apiClient != null) {
apiClient.close();
}
}
}
주의사항
Prototype Bean의 함정
@Service
@Scope("prototype")
public class FileProcessor implements DisposableBean {
@Override
public void destroy() throws Exception {
// ⚠️ Prototype Bean에서는 자동으로 호출되지 않음!
// Spring 컨테이너가 소멸을 관리하지 않음
}
}
초기화 실패 처리
@Service
public class ExternalService {
@PostConstruct
public void init() {
try {
connectToExternalAPI();
} catch (Exception e) {
throw new BeanInitializationException("외부 서비스 연결 실패", e);
}
}
}
실무 팁
- @PostConstruct/@PreDestroy 우선 사용 - 가장 직관적이고 사용하기 쉬움
- 외부 라이브러리는 initMethod/destroyMethod - 소스 수정 불가능한 경우
- Prototype Bean 주의 - 소멸 콜백이 자동으로 호출되지 않음
- 예외 처리 필수 - 초기화 실패 시 명확한 에러 메시지 제공
Bean 생명주기는 리소스 관리와 성능 최적화의 핵심입니다. 특히 파일, 네트워크 연결, 캐시 등을 다룰 때 반드시 활용해야 합니다.