빈 생명주기와 콜백
스프링 빈은 객체가 생성된 뒤에 의존성이 주입됩니다. 의존관계가 완벽하게 주입이 되어야 필요한 데이터들을 쓸 수 있는 준비도 끝이 납니다. 그렇다면 이런 세팅이 다 끝난 뒤에 연결을 하고 스프링 빈이 죽기전에 연결을 해제해야하는 경우가 생긴다면 어떻게 그 시기를 알 수 있을까요?
바로 스프링이 제공하는 콜백으로 그 시기를 알 수 있습니다. 스프링 빈의 이벤트 라이프사이클은 아래와 같습니다
========================================================================
스프링컨테이너생성 -> 스프링빈생성 -> 의존관계주입 -> 초기화콜백 -> 사용 -> 소멸전콜백 -> 스프링 종료
========================================================================
초기화 콜백과 소멸전 콜백은 각각 스프링빈에 의존관계주입이 완료, 스프링빈이 소멸 직전을 알려주는 콜백입니다.
콜백함수의 제공방법은 크게 3가지가 있습니다
InitializingBean과 DisposableBean 인터페이스에서 afterPropertiesSet과 destory를 각각 지원받아 초기화와 소멸콜백을 구현할 수 있습니다.
스프링 빈으로 등록해줄 NetworkClient를 만들어서 생성자와 setter를 만들어줍니다.
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("connect: " + url);
}
public void call(String message) {
System.out.println("call: " + url + " message = " + message);
}
//서비스 종료시 호출
public void disConnect() {
System.out.println("close + " + url);
}
@Override
public void afterPropertiesSet() throws Exception {
connect();
call("초기화 연결 메시지");
}
@Override
public void destroy() throws Exception {
disConnect();
}
}
}
LifeCycleConfig를 통해 NetworkClient를 스프링 빈으로 등록을 해주고있습니다. 여기서는 의존성주입과정은 없습니다. 다만 setUrl을 통해서 NetworkClient의 데이터 Url을 세팅해주는 부분이 있습니다.
public class BeanLifeCycleTest {
@Test
public void lifeCycleTest() {
ConfigurableApplicationContext ac = new AnnotationConfigApplicationContext(LifeCycleConfig.class);
NetworkClient client = ac.getBean(NetworkClient.class);
ac.close(); //스프링 컨테이너를 종료, ConfigurableApplicationContext 필요
}
@Configuration
static class LifeCycleConfig {
@Bean
public NetworkClient networkClient() {
NetworkClient networkClient = new NetworkClient(); // 생성
networkClient.setUrl("http://hello-spring.dev");
return networkClient;
}
}
}
출력결과를 토대로 스프링 빈의 라이프 사이클을 보면 먼저 스프링빈이 생성되고 그때 생성자호출이 됩니다. 생성과정에서 setUrl을 통해 값도 세팅이 됩니다. 그 뒤에 초기화 콜백이 호출됩니다. 따라서 connect함수도 호출되고 call함수도 호출됩니다. 마지막으로 ac.close()전에 destroy가 호출되어 disconnet가 호출된것이 보입니다.
출력결과
생성자 호출, url = null
NetworkClient.afterPropertiesSet
connect: http://hello-spring.dev
call: http://hello-spring.dev message = 초기화 연결 메시지
13:24:49.043 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Closing NetworkClient.destroy
close + http://hello-spring.dev
단점🧨
이는 스프링 초창기에 나온 방식으로 지금은 거의 쓰이지 않습니다!
이번 방법은 설정파일에서 초기화, 소멸 메서드를 지정하는 방법입니다.
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("connect: " + url);
}
public void call(String message) {
System.out.println("call: " + url + " message = " + message);
}
//서비스 종료시 호출
public void disConnect() {
System.out.println("close + " + url);
}
public void init() {
System.out.println("NetworkClient.init");
connect();
call("초기화 연결 메시지");
}
public void close() {
System.out.println("NetworkClient.close");
disConnect();
}
}
이제 설정정보에 가서 initMethod와 destoryMethod에 각각 메서드 이름을 넣어줍니다.
@Configuration
static class LifeCycleConfig {
@Bean(initMethod = "init", destroyMethod = "close")
public NetworkClient networkClient() {
NetworkClient networkClient = new NetworkClient();
networkClient.setUrl("http://hello-spring.dev");
return networkClient;
}
}
특징🍒
종료메서드의 추론
마지막은 어노테이션을 이용하는 방법입니다.
NetworkClient에서 @PostConstruct와 @PreDestory를 붙여줘서 간단하게 콜백함수들을 정해주는 방식입니다. 그러면 설정정보에서는 따로 적어줄 필요가 없습니다.
@PostConstruct
public void init() {
System.out.println("NetworkClient.init"); connect();
call("초기화 연결 메시지");
}
@PreDestroy
public void close() {
System.out.println("NetworkClient.close");
disConnect();
}
특징🍒