빈 생명주기
스프링 컨테이너는 빈 객체를 생성하고, 프로퍼티를 할당하고, 초기화를 수행하고, 사용이 끝나면 소멸시키는 일련의 과정을 관리한다.
스프링 빈은 객체를 생성하고, 의존관계 주입이 다 끝난 다음에야 필요한 데이터를 사용할 수 있는 준비가 완료된다. 스프링은 의존관계 주입이 완료되면 스프링 빈에게 콜백 메서드를 통해서 초기화 시점을 알려주는 다양한 기능을 제공한다. 또한 스프링은 컨테이너가 종료되기 직전에 소멸 콜백을 준다.
스프링 컨테이너 생성 -> 스프링 빈 생성 -> 의존관계 주입 -> 초기화 콜백 -> 사용 -> 소멸전 콜백 -> 스프링 종료
- 초기화 콜백: 빈이 생성되고, 빈의 의존관계 주입이 완료된 후 호출
- 소멸전 콜백: 빈이 소멸되기 직전에 호출
스프링은 크게 3가지 방법으로 빈 생명주기 콜백을 지원한다.
- 인터페이스(InitializingBean, DisposableBean)
- 설정 정보에 초기화 메서드, 종료 메서드 지정
- @PostConstruct, @PreDestroy 어노테이션 지원
인터페이스(InitializingBean, DisposableBean)
InitializingBean
와 DisposableBean
인터페이스를 구현해서 빈을 작성하는 방법이다. InitializingBean
의 afterPropertiesSet()
메서드는 이름 그대로 프로퍼티 설정까지 마친 뒤에 호출된다. 그리고 DisposableBean
의 destroy()
메서드는 빈이 소멸 되기 직전에 호출된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
public class BeanLifecycle implements InitializingBean, DisposableBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet");
System.out.println("프로퍼티 설정까지 마친 뒤에 호출");
}
@Override
public void destroy() throws Exception {
System.out.println("destroy");
System.out.println("빈이 소멸 되기 직전에 호출");
}
}
이 방법은 별로 권장되지 않는다. 애플리케이션 빈 코드에 스프링 인터페이스를 노출하기 때문이다. 또 다른 방법이 더 간결하기 때문이기도 하다. 반면에 인터페이스를 보고 코드의 동작방식을 이해하기 쉽다는 장점도 있다.
설정 정보에 초기화 메서드, 종료 메서드 지정
1
2
3
4
5
6
7
8
9
10
11
12
public class BeanLifecycle {
public void init() throws Exception {
System.out.println("init");
System.out.println("프로퍼티 설정까지 마친 뒤에 호출");
}
public void close() throws Exception {
System.out.println("close");
System.out.println("빈이 소멸 되기 직전에 호출");
}
}
1
2
3
4
5
6
7
8
@Configuration
public class LifecycleConfig {
@Bean(initMethod = "init", destroyMethod = "close")
public BeanLifecycle beanLifecycle() {
return new BeanLifecycle();
}
}
초기화 콜백 인터페이스를 사용히는 방법과 달리 빈 클래스에 스프링 API가 노출되지 않기 때문에 깔끔하다는 장점이 있는 반면 코드만 보고는 초기화 메소드가 호출될지 알 수 없기 때문에 코드를 이해하는 데 불편할 수 있다.
@PostConstruct, @PreDestroy 어노테이션
이 방법은 어노테이션을 활용한 방법으로 초기화를 담당할 메서드에 @PostConstruct
종료를 담당할 메서드에 @PreDestroy
를 붙여주면 된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class BeanLifecycle {
@PostConstruct
public void init() throws Exception {
System.out.println("init");
System.out.println("프로퍼티 설정까지 마친 뒤에 호출");
}
@PreDestroy
public void close() throws Exception {
System.out.println("close");
System.out.println("빈이 소멸 되기 직전에 호출");
}
}
이 방법은 최신 스프링에서 가장 권장하는 방법이다. 그리고 어노테이션 하나만 붙이면 되므로 매우 편리하다. 단점은 외부 라이브러리에 적용하지 못한다는 점이다. 만약 외부 라이브러리의 코드를 수정할 수 없지만 초기화, 종료 작업이 필요하다면 @Bean(initMethod = "init", destroyMethod = "close")
기능을 활용하면 된다.
Comments powered by Disqus.