오봉이와 함께하는 개발 블로그

Spring - 빈 생명주기 콜백(인터페이스 InitializingBean & DisposableBean, 빈 등록 초기화 & 소멸 메소드, 어노테이션 @PostConstruct & @PreDestroy 본문

BE/Spring

Spring - 빈 생명주기 콜백(인터페이스 InitializingBean & DisposableBean, 빈 등록 초기화 & 소멸 메소드, 어노테이션 @PostConstruct & @PreDestroy

오봉봉이 2022. 6. 11. 19:35
728x90

인터페이스 InitializingBean, 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 { // 의존관계 주입이 끝나면 호출해 주겠다는 뜻.
        System.out.println("NetworkClient.afterPropertiesSet");
        connect();
        call("초기화 연결 메시지");
    }

    @Override
    public void destroy() throws Exception { // 종료될 때
        System.out.println("NetworkClient.destroy");
        disconnect();
    }
}

결과

생성자 호출, url = null
NetworkClient.afterPropertiesSet
connect : http://www.hello-spring.dev
call : http://www.hello-spring.dev message : 초기화 연결 메시지
19:10:03.002 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@2c1b194a, started on Sat Jun 11 19:10:02 KST 2022
NetworkClient.destroy
close : http://www.hello-spring.dev

출력 결과를 보면 초기화 메소드가 주입 완료 후 적절하게 호출 된 것을 볼 수 있다.
또 스프링 컨테이너 종료가 호출되자 소멸 메소드가 호출 된 것도 볼 수 있다.

초기화, 소멸 인터페이스 단점

  • 스프링 전용 인터페이스기 때문에 해당 코드가 스프링 전용 인터페이스에 의존한다.
  • 초기화, 소멸 메소드의 이름을 변경할 수 없다.
  • 내가 코드를 고칠 수 없는 외부라이브러리에 적용할 수 없다.

참고

스프링 초창기에 나온 방법이고, 지금은 더 나은 방법들이 있어 잘 사용하지 않음.

빈 등록 초기화, 소멸 메서드 지정

설정 정보에 @Bean(initMethod = "init", destroyMethod = "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();
    }
}
public class BeanLifeCycleTest {
    @Test
    public void lifeCycleTest() {
        ConfigurableApplicationContext ac = new AnnotationConfigApplicationContext(LifeCycleConfig.class);
        NetworkClient client = ac.getBean(NetworkClient.class);
        ac.close();
    }

    @Configuration
    static class LifeCycleConfig {
        @Bean(initMethod = "init", destroyMethod = "close")
        public NetworkClient networkClient() {
            NetworkClient networkClient = new NetworkClient(); // 첫 생성자 호출할 때는 당연히 url은 null이 맞음
            networkClient.setUrl("http://www.hello-spring.dev");
            return networkClient;
        }
    }
}

결과

생성자 호출, url = null
NetworkClient.init
connect : http://www.hello-spring.dev
call : http://www.hello-spring.dev message : 초기화 연결 메시지
19:20:08.551 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@2c1b194a, started on Sat Jun 11 19:20:08 KST 2022
NetworkClient.close
close : http://www.hello-spring.dev

특징

  • 메소드 이름을 자유롭게 줄 수 있음.
  • 스프링 빈이 스프링 코드에 의존하지 않음
  • 코드가 아니라 설정 정보를 사용하기 때문에 코드를 고칠 수 없는 외부 라이브러리에도 초기화, 종료 메소드를 적용할 수 있다.

종료 메소드 추론

@Bean(initMethod = "init", destroyMethod = "close")에는 특별한 기능이 있다.
보통 라이브러리는 대부분 closeshutdown라는 이름의 종료 메소드를 사용하는데, destroyMethod는 기본값이 (inferred)(추론)로 등록되어 있다.
추론 기능은 말 그대로 종료 메소드의 이름을 close, shutdown등 추론해준다.
따라서 직접 스프링 빈으로 등록하면 종료 메소드는 따로 적어주지 않아도 잘 동작함.
추론 기능을 사용하기 싫다면 destroyMethod=""처럼 빈 공백을 지정하면 됨.

어노테이션 @PostConstruct, @PreDestroy

코드부터 살펴보자

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();
    }
}
@Configuration
static class LifeCycleConfig {
    @Bean
    public NetworkClient networkClient() {
        NetworkClient networkClient = new NetworkClient();
        networkClient.setUrl("http://hello-spring.dev");
        return networkClient;
    } 
}

결과

생성자 호출, url = null
NetworkClient.afterPropertiesSet
connect : http://www.hello-spring.dev
call : http://www.hello-spring.dev message : 초기화 연결 메시지
19:10:03.002 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@2c1b194a, started on Sat Jun 11 19:10:02 KST 2022
NetworkClient.destroy
close : http://www.hello-spring.dev

@PostConstruct, @PreDestroy 두 어노테이션을 사용하면 편리하게 초기화와 종료를 실행할 수 있다!

특징

  • 최신 스프링에서 가장 권장
  • 어노테이션 하나만 붙이면 되기 때문에 편리하고 가독성이 뛰어나다
  • javax.annotation.XXX이기 때문에 스프링에 종속적이지 않고 자바 표준이기 때문에 다른 컨테이너에서도 동작함.
  • 컴포넌트 스캔과 잘 어울린다.
    • 빈을 등록하는 것이 아니기 때문
    • 컴포넌트 스캔의 대상이 되도 잘 동작한다.
  • 외부 라이브러리에는 적용하지 못 한다는 단점이 있다.
    • 외부 라이브러리를 초기화 하거나 종료해야 하면 @Bean의 기능을 사용하자

정리

  • @PostConstruct, @PreDestroy 어노테이션을 사용하자
  • 코드를 고칠 수 없는 외부 라이브러리를 초기화, 종료해야 하면 @BeaninitMethod, destroyMethod를 사용하자.
출처 : 인프런 김영한 지식공유자님의 스프링 완전 정복 로드맵 강의
728x90
Comments