[Spring] 8-1. 빈 생명주기 콜백

송광호·2024년 1월 17일

[Spring]

목록 보기
35/41
post-thumbnail

Spring 시리즈는 혼자 공부하며 기록으로 남기고, 만약 잘못 학습 한 지식이 있다면 공유하며 피드백을 받고자 작성합니다.
스프링에 대해 깊게 공부해보고자 인프런의 김영한 강사님께서 강의를 진행하시는 (스프링 핵심 원리 - 기본편) 강의를 수강하며 정리하는 글입니다.
혹여나 글을 읽으시며 잘못 설명된 부분이 있다면 지적 부탁드리겠습니다.


스프링 빈이 생성되거나 죽기 일보 직전에 스프링이 빈 안에 있는 메서드를 호출해줄 수 있는 기능이다.

  • 생성되고나서 초기화 할 때 호출하고, 빈이 사라지기 일보 직전에 안전하게 종료할 수 있는 메서드를 호출한다.

빈 생명주기 콜백 시작

  • 데이터베이스 커넥션 풀이나 네트워크 소켓처럼 애플리케이션이 시작할때 필요한 연결들을 미리 해두고, 애플리케이션이 종료될 때 연결을 모두 종료하는 작업을 진행하기 위해서는 초기화와 종료 작업이 필요하다.

간단한 예제 코드(외부 네트워크에 연결하는 객체) 구현 계획

    1. NetworkClient 시작 시점에 connect() 메서드를 호출하여 연결
    1. NetworkClient 종료 시점에 disconnect() 메서드를 호출하여 연결 종료

NetworkClient 코드

public class NetworkClient {

    private String url;

    public NetworkClient() {
        System.out.println("생성자 호출 = " + url);
        connect();
        call("초기화 연결 메세지");
    }

    public void setUrl(String url) {
        this.url = url;
    }

    //서비스 시작시 호출
    public void connect() {
        System.out.println("connect : " + url);
    }

    //call
    public void call(String message) {
        System.out.println("call(); = " + url + " message = " + message);
    }

    //서비스 종료시 호출
    public void disconnect() {
        System.out.println("close " + url);
    }
}

BeanLifeCycleTest 테스트 코드

public class BeanLifeCycleTest {

    @Test
    public void lifeCycleTest() {
        ConfigurableApplicationContext ac = new AnnotationConfigApplicationContext(lifeCycleConfig.class);
        NetworkClient client = ac.getBean(NetworkClient.class);
        ac.close(); //close 메서드 사용하려면 ApplicatonContext는 안됨
    }

    @Configuration
    static class lifeCycleConfig {
        @Bean
        public NetworkClient networkClient() {
            NetworkClient networkClient = new NetworkClient();
            networkClient.setUrl("http://hello-spring.dev");
            return networkClient;
        }
    }
}

출력

  • 아마 다 null 나오지 않을까.. 싶다
생성자 호출 = null
connect : null
call(); = null message = 초기화 연결 메세지
  • null 나오는게 맞다.
  • 아무리 봐도 null인데 출력결과에 의아해 하시는데 도통 모르겠다 왤까...?
  • 당연하다 NetworkClient클래스의 생성자에서 메서드를 호출하고, setter를 통해 url값을 할당해준다.
  • 스프링 빈은 간단하게 다음과 같은 라이프 사이클을 가진다.
    객체 생성 -> 의존관계 주입

스프링 빈은 객체ㅔ를 생성하고 의존관계 주입까지 다 끝나야 필요한 데이터를 사용할 수 있는 준비가 된다.

초기화란?

  • 객체를 생성하는 작업이 아니다.
  • 객체 안에 필요한 값이 다 연결이 되는것을 초기화라고 한다.
  • 초기화 작업은 의존관계 주입이 모두 완료된 이후에 호출되어야하는데..
    개발자가 의존관계 주입이 완료된 시점을 어떻게 알 수 있을까?

스프링의 기능

  • 스프링은 의존관계 주입이 완료되면 스프링 빈에게 콜백 메서드를 통해 초기화 시점을 알려주는 다양한 기능을 제공한다.
  • 스프링 컨테이너 : 나 의존관계 주입 다 했어!
  • 또한 스프링은 스프링 컨테이너가 종료되기 직전에 소멸 콜백을 준다.

스프링 빈의 이벤트 라이프 사이클

  • 스프링 컨테이너 생성 -> 스프링 빈 생성 -> 의존관계 주입 -> 초기화 콜백 -> 사용 -> 소멸전 콜백 -> 스프링 종료
  • 초기화 콜백은 빈이 생성되고, 빈의 의존관계 주입이 완료된 후 호출된다.
  • 소멸전 콜백은 빈이 소멸되기 직전에 호출된다.

참고 : 객체의 생성과 초기화를 분리하자
생성자는 필수 정보를 받고 메모리를 할당해서 객체를 생성하는 책임이 있다. 반면에 초기화는 이렇게 생성된 값을 사용하여 외부와 연결하는 무거운 동작을 수행한다.
단일 책임 원칙을 따라서 따로 나눠서 코딩하는게 유지보수 관점에서 좋다.
분리했을때의 장점
실제 외부 커넥션 맺거나 이런걸 최초의 어떤 행위가 올 때까지 미룰 수 있다.

0개의 댓글