ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Spring Framework 시리즈 4화 – Bean의 생명주기 이해와 커스터마이징
    기술과 산업/언어 및 프레임워크 2025. 5. 21. 12:05
    728x90


    Spring Bean의 생성부터 소멸까지의 생명주기와 이를 제어하는 방법인 InitializingBean, DisposableBean, @PostConstruct, @PreDestroy 등의 애노테이션 기반 설정 방식을 실제 코드로 정리합니다.

    왜 빈 생명주기를 이해해야 하는가?

    많은 개발자가 @Component나 @Bean으로 객체를 등록하고 DI로 연결하는 데 익숙하지만, 객체가 언제 생성되고 언제 소멸되는지에 대해서는 깊이 생각하지 않습니다. 하지만 실무에서는 다음과 같은 작업이 꼭 필요합니다.

    • 데이터베이스 연결 초기화
    • 파일 핸들러나 네트워크 소켓 열기
    • 리소스 정리 및 로그 남기기
    • 커넥션 풀 종료 처리

    이 모든 과정이 Bean의 생명주기(Lifecycle)와 맞물려 있습니다.


    Spring Bean 생명주기 – 전체 흐름 요약

    객체 생성 → 의존성 주입 → 초기화 → 사용 → 소멸
    

    이 흐름을 스프링은 다음처럼 구체적인 단계로 처리합니다:

    1. 빈 인스턴스 생성 (new)
    2. 의존성 주입 (DI 수행)
    3. 초기화 콜백 실행 (PostConstruct, InitializingBean 등)
    4. 빈 사용
    5. 소멸 콜백 실행 (PreDestroy, DisposableBean 등)

    1. InitializingBean과 DisposableBean 인터페이스

    @Component
    public class ConnectionManager implements InitializingBean, DisposableBean {
    
        @Override
        public void afterPropertiesSet() {
            System.out.println("초기화 로직 실행 – afterPropertiesSet()");
        }
    
        @Override
        public void destroy() {
            System.out.println("자원 정리 로직 실행 – destroy()");
        }
    }
    

    장점

    • Spring의 고전적인 방식
    • 명확한 인터페이스 기반

    단점

    • Spring에 종속된 코드가 되어 테스트/이식성이 떨어짐

    2. @PostConstruct와 @PreDestroy (JSR-250 표준)

    @Component
    public class ConnectionManager {
    
        @PostConstruct
        public void init() {
            System.out.println("초기화 로직 실행 – @PostConstruct");
        }
    
        @PreDestroy
        public void cleanup() {
            System.out.println("자원 정리 로직 실행 – @PreDestroy");
        }
    }
    

    장점

    • 스프링 외부에서도 표준으로 인식 가능 (Java EE, Jakarta EE 등)
    • 테스트, 모듈화 측면에서 유리
    • 현재 가장 권장되는 방식

    3. @Bean 등록 시 initMethod와 destroyMethod 지정

    @Configuration
    public class AppConfig {
    
        @Bean(initMethod = "init", destroyMethod = "cleanup")
        public ConnectionManager connectionManager() {
            return new ConnectionManager();
        }
    }
    
    public class ConnectionManager {
        public void init() {
            System.out.println("초기화 로직 실행 – initMethod");
        }
    
        public void cleanup() {
            System.out.println("자원 정리 로직 실행 – destroyMethod");
        }
    }
    

    특징

    • 외부 라이브러리처럼 수정할 수 없는 클래스에 유용
    • XML 설정의 init-method, destroy-method와 유사

    참고 – 스프링 내부에서의 이벤트 순서

    Spring에서는 ApplicationContext가 내부적으로 다음과 같은 순서를 따릅니다.

    1. BeanDefinition 읽기
    2. BeanFactory 생성
    3. 빈 인스턴스 생성 및 의존성 주입
    4. BeanPostProcessor 초기화 전/후 처리
    5. 라이프사이클 콜백 실행 (PostConstruct 등)
    6. ApplicationRunner 또는 CommandLineRunner 실행
    7. 앱 사용 중
    8. 컨텍스트 종료 시 destroy 로직 실행

    실무 팁 – 종료 시점 정리 코드에 반드시 로그 남기기

    컨테이너가 정상적으로 내려가는지 확인하기 위해 @PreDestroy 혹은 DisposableBean.destroy() 내부에 반드시 로깅 코드를 포함시키는 것을 권장합니다.

    @PreDestroy
    public void shutdownLog() {
        log.info("ConnectionManager 종료됨 – 리소스 해제 완료");
    }
    

    이 로그가 없으면 커넥션이 열려있거나 파일 핸들이 릴리즈되지 않은 채 시스템이 종료되는 문제가 발생할 수 있습니다.


    마무리 – 초기화와 종료 로직은 시스템 안정성의 출발점

    빈 생명주기를 이해하고 제어하는 것은 단순한 코딩 기술이 아니라 시스템 안정성과 신뢰성의 핵심 요소입니다.

    초기화 로직과 정리 로직은 특히 배치 시스템, 외부 API 연동, DB 커넥션 관리, 비동기 처리와 같은 환경에서 더욱 중요해집니다.


    다음 5화에서는 **빈 스코프(Scope)**에 대해 학습합니다. 기본 스코프인 Singleton을 넘어 Prototype, Request, Session 등의 상황별 스코프를 비교하고, 웹 애플리케이션에서 어떻게 활용하는지를 실습합니다.

    728x90
Designed by Tistory.