[Spring]스프링 빈(Bean)을 초기화 및 종료하는 3가지 방법(Bean 생명주기 콜백)
1. 인터페이스 InitializingBean, DisposableBean 이용하기
이 방법은 인터페이스를 활용하여 빈의 생명주기를 관리하는 방법이다.
아래 예제를 보자.
public class NetworkClient implements InitializingBean, DisposableBean {
private String url;
public NetworkClient() {
System.out.println("생성자 호출, url: "+url);
}
public void setUrl(String url) {
this.url = url;
}
// 애플리케이션 시작시 호출.
public void connect() {
System.out.println("연결할 url = " + url);
}
//서비스중에 호출.
public void call(String message) {
System.out.println("url: "+url+"/message = " + message);
}
//서비스 종료시 호출.
public void disconnect() {
System.out.println("서비스 종료!");
}
// 빈 생성후 의존관계 주입이 완료되고 호출됨.
@Override
public void afterPropertiesSet() throws Exception {
connect();
call("초기화 연결 메시지");
}
// 스프링이 내려가기 직전에 호출됨
@Override
public void destroy() throws Exception {
disconnect();
}
}
위와 같이 네트워크를 관리하는 빈을 만들었다고 해보자.
이 객체에 InitializingBean과 DisposableBean 인터페이스들을 장착해주면
빈 생명주기를 관리해주는 콜백함수들을 사용할 수 있다.
(전자가 afterPropertiesSet,후자가 destroy를 오버라이드한다)
이렇게 작성하고 실제로 Configuration에서 빈을 등록하고 사용해보자.
아래는 테스트코드로 작성한 예시이다.
public class BeanTest {
@Test
public void beanTest() {
ConfigurableApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);
NetworkClient client = ac.getBean(NetworkClient.class);
ac.close();
}
@Configuration
static class Config {
@Bean
public NetworkClient networkClient() {
NetworkClient networkClient = new NetworkClient();
networkClient.setUrl("http://test.com");
return networkClient;
}
}
}
위와 같이 테스트 코드를 작성한 뒤 돌려보면 아래와 같이 로그가 찍힌다.
제대로 의존관계가 들어간 다음에 afterPropertiesSet에 의해 connect함수와 call함수가 호출되는 것을 볼 수 있다.
이 인터페이스로 콜백을 사용하는 방법은 아래와 같은 단점을 가진다.
- 초기화, 소멸 인터페이스 단점 이 인터페이스는 스프링 전용 인터페이스다. 해당 코드가 스프링 전용 인터페이스에 의존한다.
- 초기화, 소멸 메서드의 이름을 변경할 수 없다.
- 내가 코드를 고칠 수 없는 외부 라이브러리에 적용할 수 없다.
이 방법은 아주 옛날에 스프링 초기시절에 사용되던 방법으로
위의 한계점들로 인해 지금은 뒤에 나올 방법들을 더 권장하고 있다.
가급적 이 방법보다는 아래의 방법들을 사용하자.
2. 빈 등록시 초기화, 소멸 메서드 등록하기
설정 정보에 @Bean(initMethod = "init", destroyMethod = "close") 처럼 초기화, 소멸 메서드를 지정할 수 있다.
아래는 그 예시이다.
public class BeanTest {
@Test
public void beanTest() {
ConfigurableApplicationContext ac = new AnnotationConfigApplicationContext(Config.class);
NetworkClient client = ac.getBean(NetworkClient.class);
ac.close();
}
@Configuration
static class Config {
//빈에서 초기화, 소멸 메서드를 지정
@Bean(initMethod = "init",destroyMethod = "close")
public NetworkClient networkClient() {
NetworkClient networkClient = new NetworkClient();
networkClient.setUrl("http://test.com");
return networkClient;
}
}
}
NetworkClient코드에 함수명들을 설정에서 지정해줬던 init, close로 수정해준다.
public class NetworkClient {
private String url;
public NetworkClient() {
System.out.println("생성자 호출, url: "+url);
}
public void setUrl(String url) {
this.url = url;
}
// 애플리케이션 시작시 호출.
public void connect() {
System.out.println("연결할 url = " + url);
}
//서비스중에 호출.
public void call(String message) {
System.out.println("url: "+url+"/message = " + message);
}
//서비스 종료시 호출.
public void disconnect() {
System.out.println("서비스 종료!");
}
public void init() throws Exception {
connect();
call("초기화 연결 메시지");
}
public void close() throws Exception {
disconnect();
}
}
이렇게 작성하고 테스트코드를 돌려보면 처음과 같은 결과가 나온다.
콜백이 잘 호출되는 것을 볼 수 있다.
* @Bean의 종료메서드 추론 기능에 대하여
우리가 사용하는 @Bean은 좀 특이한 기능이 있는데
바로 종료메서드를 따로 지정하지 않을 시
스프링이 종료 메서드를 추론해서 스프링이 자동으로 호출해준다는 것이다.
바로 테스트를 해보자
설정정보에서 destroyMethod를 지워주고 돌려본다.
@Configuration
static class Config {
@Bean(initMethod = "init")
public NetworkClient networkClient() {
NetworkClient networkClient = new NetworkClient();
networkClient.setUrl("http://test.com");
return networkClient;
}
}
위와 같이 코드를 지우고 돌리면
우리는 종료메서드 지정을 지웠는데도 서비스 종료! 로그가 찍히는 것을 볼 수 있다.
이 기능이 추론기능인데
등록된 Bean안에 우리가 일반적으로 많이 쓰는 종료 메서드들의 이름(close, shutdown 등)들의 메서드가 있으면
스프링이 종료될 때 자동으로 호출해준다.
간혹 우리가 빈을 등록하고 스프링 종료시점에 의도치 않게 특정 메서드가 작동한다면
이 기능을 떠올리면 된다.
만약 추론 기능을 사용하기 싫다면 destroyMethod="" 처럼 빈 공백을 지정하면 된다.
3. 어노테이션으로 콜백 사용하기(@PostConstruct, @PreDestroy)
이 방법은 콜백으로 등록하고 싶은 메소드에 어노테이션을 달아
빈 콜백 메서드로 등록해주는 방법이다.
다음은 그 예이다.
//NetworkClient
@PostConstruct
public void init() throws Exception {
connect();
call("초기화 연결 메시지");
}
@PreDestroy
public void close() throws Exception {
disconnect();
}
NetworkClient라는 빈 안에 init과 close라는 두 함수를 콜백으로 등록하고 싶을 때
각각 어노테이션을 달아주면 끝이다.
@PostConstruct , @PreDestroy 이 두 애노테이션을 사용하면 가장 편리하게 초기화와 종료를 실행할 수 있다.
@PostConstruct, @PreDestory의 특징은 다음과 같다.
- 최신 스프링에서 가장 권장하는 방법이다.
- 애노테이션 하나만 붙이면 되므로 매우 편리하다.
- 패키지를 잘 보면 javax.annotation.PostConstruct 이다. 스프링에 종속적인 기술이 아니라 자바 표준이다. 따라서 스프링이 아닌 다른 컨테이너에서도 동작한다.
- 컴포넌트 스캔과 잘 어울린다.
- 유일한 단점은 외부 라이브러리에는 적용하지 못한다는 것이다. 외부 라이브러리를 초기화, 종료 해야 하면 @Bean의 기능을 사용하자.
4. 결론
일반적으로 초기화나 종료 메서드 콜백이 필요할 때는
@PostConstruct, @PreDestroy를 활용하자.
그 외의 코드를 고칠 수 없는 외부 라이브러리의 초기화, 종료가 필요하다면 @Bean에서 initMethod, destroyMethod 기능을 활용하자.
Reference
이 포스팅은 아래의 강좌를 참고하여 만들어졌습니다.
- 스프링 핵심 원리-기본편
'Backend > Spring' 카테고리의 다른 글
ipTIME의 DDNS를 이용하여 운영 서버 구축하기(포트포워딩) (1) | 2020.10.30 |
---|---|
[Spring]빈 스코프(Bean Scope)의 종류 및 개념 (0) | 2020.10.27 |
[Spring] 스프링의 빈(Bean) 생명주기 콜백의 개념 및 예제 (0) | 2020.10.24 |
[SpringBoot] ajax로 사진 업로드와 삭제, 썸네일 미리보기 기능 구현하기 (4) | 2020.07.30 |
[Spring]게시글 사진 업로드기능 구현(MultipartHttpServletRequest) (0) | 2020.07.16 |