![빈 생명 주기(Bean Life Cycle)와 콜백(callback)](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FukWRn%2FbtsCw799PSz%2FE26YEi4Y6jeY5zK1dIk931%2Fimg.png)
빈 초기화와 소멸
스프링 컨테이너(DI 컨테이너라고도 불린다)에서 관리되는 빈의 생명 주기는 크게 세 가지 단계로 나뉜다.
- 빈 초기화
- 빈 사용
- 빈 소멸
스프링 빈은 객체가 생성되고 의존관계 주입이 끝난 후에 사용할 수 있다. 그렇기 때문에 DB Connection Pool(DBCP), Network Socket과 같이 애플리케이션 시작 시점에 미리 연결하고 종료 시점에 연결을 끊는 작업을 진행하는 경우는 의존관계 주입이 끝난 후 빈 초기화 작업이 이루어 져야 하고, 애플리케이션 종료 시점에 빈 소멸이 되어야 한다. 그렇다면 개발자가 이 시점을 어떻게 알고 프로그래밍을 할 수 있을까?
스프링에서는 친절하게 개발자에게 의존관계 주입이 완료된 시점과 스프링 컨테이너가 종료되는 시점에 콜백(callback)기능을 제공한다. 크게 3가지 방법이 있는데 이번 포스팅은 이에 대해서 정리하는 내용이다.
- 스프링 인터페이스 설정(InitializingBean, DisposableBean)
- 애너테이션 기반 설정(@PostConstruct, @PreDestroy)
- 자바 기반 설정(@Bean 설정 정보에 메서드 지정 : initMethod, destroyMethod)
InitializingBean, DisposableBean
- 빈 생성 후 빈 초기화 작업을 할 수 있도록 InitializingBean
- 스프링 종료 전에 전처리를 할 수 있도록 DisposableBean
스프링에서는 위와 같은 인터페이스를 제공한다. 이 인터페이스를 구현하면 각각 afterPropertiesSet(), destroy() 메서드로 빈 생성 후 초기화, 빈 소멸 전처리 작업을 할 수 있다.
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
public class NetworkClient implements InitializingBean, DisposableBean {
public NetworkClient() {
}
//서비스 시작시 호출
public void connect() {
...
}
//서비스 종료시 호출
public void disConnect() {
...
}
@Override
public void afterPropertiesSet() throws Exception {
connect();
}
@Override
public void destroy() throws Exception {
disConnect();
}
}
이 방법은 스프링 초기에 쓰였으며 지금은 아래와 같은 이유로 거의 쓰이지 않는다.
- 스프링 전용 인터페이스라 스프링에 종속적이다.
- 초기화, 소멸 메소드 이름을 변경할 수 없다.
- 코드를 고칠 수 없는 외부 라이브러리에 적용할 수 없다.
@PostConstruct, @PreDestroy
스프링 인터페이스를 사용한 방법의 단점들로 최신 스프링에서는 @PostConstruct, @PreDestroy 애너테이션 사용을 권장하고 있다.
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class NetworkClient {
public NetworkClient() {
}
//서비스 시작시 호출
public void connect() {
...
}
//서비스 종료시 호출
public void disConnect() {
...
}
@PostConstruct
public void init() {
connect();
}
@PreDestroy
public void close() {
disconnect();
}
}
이 방식을 최신 스프링에서 권장하는 이유는 아래와 같은 장점이 있기 때문이다.
- 애너테이션만 붙이면 되므로 매우 편리하다.
- 애너테이션 패키지를 보면 JSR-250이라는 자바 표준 애너테이션이라 스프링이 아니여도 사용 가능하다.
하지만 유일한 단점으로 외부 라이브러리에 적용하지 못한다는 점이다. (이 점은 자동으로 스프링 빈을 설정할 경우 나오는 문제이다.) 이런 경우는 다음과 같은 방법을 사용해야 한다.
@Bean 설정 정보에 메서드 지정
@Bean(initMethod = "init", destroyMethod = "close")
와 같이 각각 초기화, 소멸 메서드를 지정할 수 있다.
public class NetworkClient {
public NetworkClient() {
}
//서비스 시작시 호출
public void connect() {
...
}
//서비스 종료시 호출
public void disConnect() {
...
}
public void init() {
connect();
}
public void close() {
disconnect();
}
}
@Configuration
static class TestConfig {
@Bean(initMethod = "init", destroyMethod = "destroy")
public NetworkClient networkClient() {
...
return networkClient;
}
}
이 방법은 아래와 같은 특징이 있다.
- 메서드 이름을 줄 수 있다.
- 외부 라이브러리에도 초기화, 종료 메서드를 적용할 수 있다.
- @Bean의 destroyMethod는 inferred(추론) 기능이 있다.
- 이 기능으로 close 혹은 shutdown 이라는 이름의 메서드를 자동으로 호출한다.
- 이 때문에 직접(수동으로) 스프링 빈 등록을 하면 종료 메서드를 따로 적어주지 않아도 잘 동작한다.
- 추론 기능을 사용하기 싫으면 destroyMethod = "" 와 같이 공백으로 둔다.
정리
- 스프링에서는 객체가 생성되고 의존관계 주입이 완료된 시점에, 혹은 빈 소멸 전에 전처리 작업이 필요한 시점에 작업을 할 수 있도록 크게 3가지 방법을 제공한다.
- 기본적으로 애너테이션을 활용한 방식(@PostConstruct, @PreDestroy)을 사용하자.
- 단, 외부 라이브러리를 사용하는 코드에는 빈 설정 정보에 초기화, 소멸 메서드(initMethod, destroyMethod)를 지정해주자.
'Backend > Spring' 카테고리의 다른 글
스프링부트3.2.3 HTTP메세지 로그레벨 변경 (debug->trace) (0) | 2024.03.10 |
---|---|
빈 스코프(Bean Scope)와 스코프가 다른 빈 주입 (0) | 2023.12.27 |
@Autowired 빈 설정 방식 (+ @Qualifier, @Primary) (0) | 2023.12.22 |
다양한 의존관계 주입 방법 (생성자 주입을 선택해야 하는 이유) (0) | 2023.12.18 |
스프링 빈 설정하는 방법 (XML, @Configuration, @Component) (1) | 2023.12.17 |
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!