빈 생명주기 콜백

inhalin·2022년 7월 27일
0

김영한님의 스프링 핵심 원리 - 기본편 강의를 듣고 정리한 내용입니다.

기본 설명

애플리케이션 시작 시점에 연결했다가(초기화 작업) 종료할때 연결을 모두 닫아주는 작업(종료 작업)이 어떻게 이루어지는지 확인한다.

NetworkClient 객체에는 url 필드와 생성자, 수정자 setUrl, 시작시 호출하는 connect, 연결 작업을 하는 call, 종료시 호출하는 discconnect 메서드가 있다. 각 메서드는 간단하게 자신의 이름과 url을 출력한다.

public class NetworkClient {
	String url;
    
    public NetworkClient() {
    	System.out.println("생성자 호출, url = " + url);
        connect();
        call("초기화 연결 메시지");
    }
    
    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);
    }
}

NetworkClient를 스프링 빈으로 등록해주는데, 객체를 생성하고 나서 setUrl로 url을 설정해준다. 그러면 다음과 같은 출력 결과를 볼 수 있다.

생성자 호출, url = null
connect: null
call: null message = 초기화 연결 메시지

객체가 생성되는 시점에는 url값이 없어서 전부 null로 나오게 된다.

스프링 빈은 먼저 객체를 생성하고 나서 의존관계를 주입한다. 스프링에서 의존관계 주입이 끝난 다음에 초기화 콜백을 주고 스프링 컨테이너 종료 직전에 소멸전 콜백을 준다.

빈 생명주기 콜백 지원 방법

InitializingBean, DisposableBean

  • 스프링 전용 인터페이스이다.
  • InitializingBeanafterPropertiesSet()에는 의존관계 주입이 끝난 후에 실행할 내용을 써준다.
  • DisposableBeandestroy()에는 스프링 컨테이너가 죽기 직전에 실행할 내용을 써준다.
  • 지금은 이 방식은 거의 사용하지 않는다.
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

public class NetworkClient implements InitializingBean, DisposableBean {
    //생략
    
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("NetworkClient.afterPropertiesSet");
        connect();
        call("초기화 연결 메시지 ");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("NetworkClient.destroy");
        disconnect();
    }
}
생성자 호출, url = null
NetworkClient.afterPropertiesSet
connect: https://spring-core.dev
call: https://spring-core.dev message = 초기화 연결 메시지 
20:58:35.714 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Closing
NetworkClient.destroy
close: https://spring-core.dev

설정 정보에 초기화 메서드, 종료 메서드 지정

  • 설정 정보에 @BeaninitMethoddestroyMethod를 지정해준다.
    • destroyMethod는 추론 기능이 있어서 생략하면 자동으로 close, shutdown 이름을 가진 메서드를 호출한다. 자동 추론을 사용하고 싶지 않으면 빈 문자열을 지정해주면 된다.
  • 이렇게 쓰면 메서드 이름을 내가 원하는대로 자유롭게 쓸 수 있다.
  • 코드를 수정할 수 없는 외부 라이브러리를 가져다 쓸때도 초기화, 종료 메서드를 쓸 수 있다.
public class NetworkClient {
    // 생략
    
    public void init() {
        System.out.println("NetworkClient.init");
        connect();
        call("초기화 연결 메시지 ");
    }

    public void close() {
        System.out.println("NetworkClient.destroy");
        disconnect();
    }
}
@Configuration
static class LifeCycleConfig {

    @Bean(initMethod = "init", destroyMethod = "close")
    public NetworkClient networkClient() {}
생성자 호출, url = null
NetworkClient.init
connect: https://spring-core.dev
call: https://spring-core.dev message = 초기화 연결 메시지 
21:10:56.197 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Closing
NetworkClient.destroy
close: https://spring-core.dev

@PostConstruct, @PreDestroy

  • 스프링에서 권장하는 방식이고 스프링에 종속적이지 않아서 다른 컨테이너에서도 동작한다.
  • 애노테이션만 붙여주면 되기 때문에 쓰기도 편하고 유지보수도 편하다.
  • 단, 외부 라이브러리에는 사용할 수 없어서 그 때는 바로 위에 있는 @Bean 기능을 써주면 된다.
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

public class NetworkClient {
    // 생략

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

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

실행 결과는 위와 같다.

0개의 댓글