객체 생성 → 의존관계 주입

스프링 빈은 객체 생성, 의존관계 주입이 끝나야 필요한 데이터를 사용할 수 있음, 객체의 데이터 초기화는 의존관계 주입이 끝난 뒤에 가능

 

콜백을 통해서 초기화 시점과 종료 시점을 알려줌

 

1) 스프링 컨테이너 생성

2) 스프링 빈 생성

3) 의존관계 주입

4) 초기화 콜백

5) 빈 사용

6) 소멸 전 콜백

7) 스프링 종료

 

객체의 생성과 초기화를 분리

생성자는 객체 생성을 위한 정보를 받고, 메모리에 객체를 생성하는 역할

초기화는 생성된 객체를 활용하여 외부와 커넥션을 연결하는 무거운 동작을 수행

=> 생성자 안에서 무거운 초기화 작업을 하지 않고, 객체를 생성하는 부분과 초기화하는 부분을 분리(별도의 초기화 메서드)

 

 

스프링의 콜백 지원

1) InitializingBean, DisposableBean 인터페이스 => 사용 X

- 스프링 전용 인터페이스라서, 스프링에 의존적임

- 인터페이스의 메서드를 오버 라이딩하기 때문에, 초기화/소멸 메서드의 이름 변경 불가

- 코드 수정이 불가능한 외부 라이브러리에 적용 불가

 

2) 설정 정보에 초기화/소멸 메서드 지정 => 외부 라이브러리 연동에 사용

- @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 msg) {
        System.out.println("call = " + url + " / msg = " + msg);
    }

    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 LifeCycleTest {

    @Test
    public void lifeCycleTest() {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(LifeCycleConfig.class);
        ac.close();
    }

    @Configuration
    static class LifeCycleConfig {
        @Bean(initMethod = "init", destroyMethod = "close")
        public NetworkClient networkClient() {
            NetworkClient nc = new NetworkClient();
            nc.setUrl("http://hello.com");
            return nc;
        }
    }
}
생성자 url : null
NetworkClient.init
connect : http://hello.com
call = http://hello.com / msg = 메시지~~~~
16:19:33.041 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@45018215, started on Sun Apr 18 16:19:32 KST 2021
NetworkClient.close
close = http://hello.com

설정 클래스 LifeCycleConfig를 보고 객체 생성 → 의존관계 주입 초기화 콜백 메서드(init메서드) → 사용 소멸 콜백 메서드(close메서드) → 종료(ac.close())

 

- 초기화/소멸 메서드 이름을 맘대로 할 수 있음

- 스프링에 의존 X

- 설정 정보의 @Bean에 지정하기 때문에 외부 라이브러리에도 적용이 가능

- destroyMethod이름을 따로 지정하지 않으면 close나 shutdown이라는 메서드를 호출함 (기본값이 추론 / inferred)

(라이브러리의 종료 메서드는 대부분 close나 shutdown)

 

 

3) @PostConstruct, @PreDestroy 어노테이션 => 사용 권장

- 초기화 메서드에 @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 msg) {
        System.out.println("call = " + url + " / msg = " + msg);
    }

    public void disConnect() {
        System.out.println("close = " + url);
    }

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

    // 소멸 메서드
    @PreDestory
    public void close() {
        System.out.println("NetworkClient.close");
        disConnect();
    }
}

- 어노테이션만 붙이면 돼서 간편함

- @PostConstruct, @PreDestroy는 스프링에 종속된 것이 아니고 자바 표준임

- @Bean을 사용하지 않기 때문에 컴포넌트 스캔과 잘 어울림

- 단점은 설정 클래스에 작성하는 것이 아니라 외부 라이브러리에는 적용을 못함

 

 

정리

- 초기화/소멸 메서드 지정을 위해서 @PostConstruct, @PreDestroy를 사용

- 외부 라이브러리에 적용해야 할 때는 @Bean의 initMethod, destroyMethod를 사용