빈 생명주기와 콜백

스프링 프로젝트를 서버에 올리기 전에 DB 연결, 네트워크 연결 등을 미리 해두면 응답 속도가 빨라지고 이런 연결들은 애플리케이션이 종료될때 안전하게 종료 되어야한다.

객체의 초기화와 종료 작업이 필요한데 우선 예제 코드부터 작성
애플리케이션 시작 시점에 연결 connect() -> 사용 call() -> 종료 disconnect()

public class NetworkClient {
    private String url;

    public NetworkClient() {
        System.out.println("생성자  호출, url = " + url);
        connenct();
        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);
    }

}

테스트 코드

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

실행하면 당현히 url 정보는 nul 값이 나온다.
그 이유는 스프링 빈은 객체를 생성하고 나서 의존 관계를 주입하는데 생성자 부분에서 url 정보 없이 connect()가 호출되었기 때문이다.

스프링빈의 이벤트 라이프 사이클
스프링컨테이너생성 -> 스프링빈생성 -> 의존관계주입 -> 초기화콜백 -> 사용 -> 소멸전콜백 -> 스프링 종료

  • 초기화 콜백: 빈이 생성되고, 빈의 의존관계 주입이 완료된 후 호출
  • 소멸전 콜백: 빈이 소멸되기 직전에 호출

스프링은 3가지 방법으로 빈 생명주기 콜백 지원

  • 인터페이스(InitializingBean, DisposableBean)
  • 설정 정보에 초기화 메서드, 종료 메서드 지정
  • @PostConstruct, @PreDestroy 애노테이션 지원

인터페이스 사용

public class NetworkClient implements InitializingBean, DisposableBean {
    ...
    //InitializingBean에서 지원
    @Override
    public void afterPropertiesSet() throws Exception {
        connect();
        call("초기화 연결 메시지");
    }
    
    //DisposableBean에서 지원
    @Override
    public void destroy() throws Exception {
        disConnect();
    }
}

단점

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

인터페이스 방식은 초창기 방법이라 지금은 거의 사용하지 않는다.

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

@Bean(initMethod = “초기화 콜백 메소드 명”, destroyMethod = “소멸전 콜백 메소드 명”)
서비스 시작시, 종료 직전 호출할 메소드를 구현하고 설정 정보에 위와 같이 지정하면 끝이다.

특징

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

종료 메서드 추론

@Bean에 destroyMethod에 특별한 기능이 있다.
라이브러리는 대부분 close(), shutdown() 이름의 종료 메소드를 사용하기때문에 디폴트로 close, shutdown 메소드를 찾아서 호출해준다. 결론은 destroyMethod를 지워도 종료 메소드는 호출이 된다.
사용하기 싫으면 destroyMethod=”” 처럼 빈 공백으로 지정

어노테이션

시작시 호출할 메소드에는 @PostConstruc, 종료 직전 호출할 메소드에는 @PreDestroy를 붙여주면 끝이다. 최신 스프링에서 가장 권장하는 방법이고 자바 표준 기술이기 때문에 스프링이 아닌 다른 컨테이너를 사용한다고 해도 문제없다.
유일한 단점은 외부 라이브러리에 사용하지 못한다는 것인데 그때는 @Bean()에 직접 등록해주면 된다.

정리

  • @PostConstruct, @PreDestroy 어노테이션을 사용
  • 코드를 고칠 수 없는 외부 라이브러리를 초기화, 종료해야 하면 @Bean의 initMethod , destroyMethod 사용

카테고리:

업데이트:


Comments