Spring - 빈 생명주기(Bean LifeCycle)

박민수·2024년 12월 29일
post-thumbnail

1. 개요

Spring 프레임워크는 객체 간의 의존성을 관리하고, 애플리케이션 개발을 간소화하기 위해 IoC(제어의 역전) 컨테이너를 활용한다. 이 컨테이너는 애플리케이션의 구성 요소를 Spring Bean으로 관리하며, 초기화, 의존성 주입, 소멸 등 객체의 생명주기를 체계적으로 제어한다. 이 글에서는 Spring Bean의 개념, 생명주기, 초기화 및 소멸 전 콜백 메소드 구현 방식을 정리하고자 한다.

2. Spring Bean이란?

Spring Bean은 Spring IoC 컨테이너가 관리하는 객체를 의미한다. 일반적으로 애플리케이션의 주요 비즈니스 로직을 구현한 클래스를 Spring Bean으로 등록하며, 설정 파일(XML), 애노테이션, 또는 Java Config 방식으로 Bean을 정의할 수 있다.

3. 빈 생명주기

Spring Bean의 라이프사이클은 아래와 같은 단계로 이루어진다.

스프링 IoC 컨테이너 생성 → 스프링 빈 생성 → 의존관계 주입 → 초기화 콜백 메소드 호출 → 사용 → 소멸 전 콜백 메소드 호출 → 스프링 종료

1. Spring IoC 컨테이너 생성

  • Spring 애플리케이션이 실행되면 IoC(제어의 역전) 컨테이너가 생성된다.
  • IoC 컨테이너는 애플리케이션 컨텍스트(ApplicationContext)로 구현된다.
  • Bean 정의 정보를 읽고, 관리할 준비를 한다.
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

2. Instantiation (객체 생성)

  • Spring IoC 컨테이너가 설정을 읽고 Bean 객체를 생성한다.
  • 이 단계에서 객체는 아직 프로퍼티가 설정되지 않은 상태이다.

3. Populating Properties (의존성 주입)

  • Spring은 DI를 통해 Bean에 필요한 의존성을 주입한다.
  • XML 설정, @Autowired 애노테이션, 또는 Java Config에서 설정된 값들이 주입된다.

4. Bean Initialization (초기화)

  • Bean이 사용되기 전 초기화 과정을 거친다.
  • @PostConstruct 또는 InitializingBean의 afterPropertiesSet() 메서드 사용
  • XML에서 init-method 속성을 정의할 수도 있다.

5. Bean Ready (활용 가능 상태)

  • Bean이 애플리케이션에서 사용 가능한 상태가 된다.
  • 애플리케이션의 서비스 호출 등 주요 작업이 수행된다.

6. Bean Destruction (소멸)

  • 컨테이너가 종료되면 Bean 소멸 과정이 실행된다.
  • @PreDestroy 또는 DisposableBean의 destroy() 메서드 사용
  • XML 설정에서 destroy-method 속성을 지정

4. 초기화 및 소멸 전 콜백 메소드

스프링은 크게 4가지 방법으로 Bean 생명주기 콜백을 관리한다.

  1. @PostConstruct와 @PreDestroy 애노테이션
  2. InitializingBean과 DisposableBean 인터페이스
  3. XML 설정
  4. Java Config 설정

4.1. @PostConstruct와 @PreDestroy 애노테이션

  • Java의 표준 애노테이션(javax.annotation 패키지)
    • 초기화: @PostConstruct
    • 소멸: @PreDestroy
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

@Component
public class MyBean {
    @PostConstruct
    public void init() {
        System.out.println("초기화 메서드 실행 (@PostConstruct)");
    }

    @PreDestroy
    public void destroy() {
        System.out.println("소멸 메서드 실행 (@PreDestroy)");
    }
}

장점

  • 간결하고 직관적인 애노테이션 기반 설정으로 코드 가독성이 높습니다.
  • javax.annotation 패키지에 포함된 JSR-250 표준(Java Specification Request)이다.
  • 따라서 스프링 프레임워크에 종속되지 않고, Java EE, Jakarta EE, 또는 다른 컨테이너에서도 동작할 수 있다.
  • 스프링 환경에서는 별도의 설정 없이도 기본적으로 지원되며, 코드가 간결하고 직관적이어서 가장 널리 사용된다.

단점

  • 초기화/소멸 로직의 순서를 제어할 수 없으며, 복잡한 커스터마이징에는 한계가 있다.
  • Java의 javax.annotation에 의존하기 때문에 Java 9 이후 환경에서는 추가적인 모듈 설치가 필요할 수 있다.

4.2. InitializingBean과 DisposableBean 인터페이스

  • Spring의 특정 인터페이스를 구현하여 초기화와 소멸 메서드 정의
    • 초기화: afterPropertiesSet()
    • 소멸: destroy()
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

@Component
public class MyBean implements InitializingBean, DisposableBean {

    @Override
    public void afterPropertiesSet() {
        System.out.println("초기화 메서드 실행 (InitializingBean)");
    }

    @Override
    public void destroy() {
        System.out.println("소멸 메서드 실행 (DisposableBean)");
    }
}

장점

  • Java 표준 애노테이션을 사용하지 않는 프로젝트에서 유용
  • 간단한 초기화/소멸 작업을 메서드 오버라이드만으로 쉽게 구현할 수 있다.

단점

  • Spring 프레임워크에 강하게 종속되어 다른 컨테이너에서는 사용할 수 없다.
  • 여러 인터페이스를 구현할 경우 Bean 클래스의 유연성이 떨어질 수 있다.
  • 최신 Spring Boot 기반 프로젝트에서는 거의 사용되지 않는다.

4.3. XML 설정

  • XML 파일에서 초기화와 소멸 메서드를 명시적으로 지정
    • 초기화: init-method 속성
    • 소멸: destroy-method 속성
<bean id="myBean" class="com.example.MyBean" init-method="init" destroy-method="cleanup"/>
public class MyBean {
    public void init() {
        System.out.println("초기화 메서드 실행 (XML 설정)");
    }

    public void cleanup() {
        System.out.println("소멸 메서드 실행 (XML 설정)");
    }
}

장점

  • 초기화와 소멸 로직을 XML에서 정의하므로 코드와 설정을 분리할 수 있다.
  • 코드 수정 없이도 설정 변경이 가능해 외부 구성 관리에 유리하다.

단점

  • 초기화/소멸 메서드 설정이 코드가 아닌 XML에 분산되어 있어 가독성이 낮고 유지보수가 어렵다.
  • 현대 Spring 프로젝트에서는 XML 설정을 거의 사용하지 않는다.

4.4. Java Config 설정

  • @Configuration 클래스에서 @Bean 애노테이션으로 초기화와 소멸 메서드를 지정
    • 초기화: initMethod 속성
    • 소멸: destroyMethod 속성
@Configuration
public class AppConfig {

    @Bean(initMethod = "init", destroyMethod = "cleanup")
    public MyBean myBean() {
        return new MyBean();
    }
}

public class MyBean {
    public void init() {
        System.out.println("초기화 메서드 실행 (Java Config)");
    }

    public void cleanup() {
        System.out.println("소멸 메서드 실행 (Java Config)");
    }
}

장점

  • 코드 기반 설정으로 IDE의 강력한 지원을 받을 수 있으며, 타입 안전성이 보장된다.
  • 현대적인 Spring 프로젝트에서 권장되는 방식이다.

단점

  • 초기화/소멸 로직이 Bean 클래스 내부에 포함되므로 코드가 분산될 위험이 있다.
  • XML 설정과 함께 사용할 경우 설정 관리가 복잡해질 수 있다.
profile
안녕하세요 백엔드 개발자입니다.

0개의 댓글