스프링/Core

빈 생명주기 콜백

maeng0830 2023. 2. 2. 16:57

어플리케이션 시작 시에 데이터베이스, 네트워크 소켓 등을 연결 하고, 어플리케이션 종료 시에 연결을 종료하기 위해서는

객체의 초기화, 소멸 작업이 필요하다.

 

스프링은 빈 객체를 생성하고, 의존관계 주입이 다 끝난 뒤에 필요한 데이터를 사용할 수 있는 준비가 완료된다.

따라서 객체의 초기화 작업은 의존관계 주입이 끝난 후 이뤄져야한다.

 

스프링은 의존관계 주입 후, 초기화 콜백을 호출하여 객체의 초기화 작업을 지원한다.

또한 스프링 빈이 소멸되기 직전에 소멸 콜백을 호출하여 객체의 소멸 작업을 지원한다.

 

초기화 콜백(초기화 메서드), 소멸 콜백(소멸 메서드)을 빈 생명주기 콜백이라고 부르며,

스프링은 크게 세 가지 방법을 통해 빈 생명주기 콜백을 지원한다.

 

인터페이스(InitilizingBean, DisposableBean)

아래의 코드는 인터페이스(InitilizingBean, DisposableBean)를 통해 빈 생명주기 콜백을 사용한다.

 

InitializingBeanafterPropertiesSet을 통해 객체 초기화를 지원하며,

DisposableBeandestroy를 통해 객체 소멸을 지원한다.

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();
	}
}

인터페이스를 활용한 방법은 아래와 같은 단점들 때문에 현재는 잘 사용되지 않는다.

  • 스프링 전용 인터페이스들이기 때문에, 스프링 의존적인 코드가 작성된다.
  • 초기화, 소멸 메서드의 이름을 변경할 수 없다.
  • 개인이 코드를 수정할 수 없는 외부 라이브러리에 적용할 수 없다.

설정 정보 활용

아래의 코드는 스프링 빈 설정 정보에 초기화, 소멸 메서드를 지정하여 빈 생명주기 콜백을 사용하는 방법이다.

 

@Bean을 통해 스프링 빈을 지정할 때 initMethod, destroyMethod를 지정하여

객체의 초기화, 소멸 시에 해당 메소드를 호출할 수 있다.

// <LifeCycleConfig.java>
@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.java>
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();
	}
}

애노테이션(@PostConstruct, @PreDestroy)

마지막으로 @PostConstruct, @PreDestroy를 활용한 방법은 가장 간단하며, 자주 사용되는 방법이다.

 

사용할 초기화 메서드, 소멸 메서드에 각각 @PostConstruct, @PreDestory를 지정해주면 된다.  

아래는 예시 코드이다.

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);
	}

	@PostConstruct
	public void init() {
		System.out.println("NetworkClient.init");
		connect();
		call("초기화 연결 메시지");
	}

	@PreDestroy
	public void close() {
		System.out.println("NetworkClient.close");
		disConnect();
	}
}

애노테이션을 활용한 방법은 매우 편리하며, 자바 표준 기술이기 때문에 스프링 종속적이지 않다.

 

유일한 단점은 외부 라이브러리에 활용하지 못한다는 것인데,

외부 라이브러리를 초기화, 종료해야한다면 설정 정보(initMethod, destroyMethod)를 활용하자.


출처: 스프링 핵심 원리 - 기본편 - 인프런 | 강의 (inflearn.com)