Spring Bean의 생명주기

Yebali·2021년 2월 15일
0

약간의_Spring

목록 보기
8/30

Spring Bean의 생명주기

Spring에서 관리하는 Bean들은 아래와 같은 생명주기를 가진다.

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

Spring Bean은 객체 생성과 의존관계 주입이 끝나야 사용할 준비가 완료된다.
따라서 초기화 작업은 의존관계 주입 후 호출된다.

Spring은 Bean을 사용 전, 후 Bean에 대해 특정 작업을 하고 싶을 때
의존관계가 주입된 직후, 또는 Bean이 소멸하기 전 시점을 알 수 있도록 '초기화 콜백'과 '소멸 전 콜백'을 제공한다.

해당 콜백을 사용하는 방법 3가지를 알아보자.

1. InitializingBean, DisposableBean 인터페이스

public class BeanLifeCycleTest {

    @Test
    public void lifecycle() {
        ConfigurableApplicationContext ac = new AnnotationConfigApplicationContext(LifeCycleConfig.class);
        TestBean bean = ac.getBean(TestBean.class);

        ac.close();
    }

    @Configuration
    static class LifeCycleConfig {
        @Bean
        public TestBean networkClient() {
            TestBean testBean = new TestBean();

            return testBean;
        }
    }
}

TestBean 을 생성하고 ac.close()를 통해 Bean을 소멸시킨다.

public class TestBean implements InitializingBean, DisposableBean {

    public TestBean() {
    }

    // 서비스 시작 시 호출
    public void whenServiceStart() {
        System.out.println("TestBean.whenServiceStart");
    }

    //서비스 종료 시 호출
    public void whenServiceDone() {
        System.out.println("TestBean.whenServiceDone");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("TestBean.afterPropertiesSet");
        whenServiceStart();
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("TestBean.destroy");
        whenServiceDone();
    }
}

InitializingBean, DisposableBean인터페이스의 afterPropertiesSet, destroy 메서드를 구현하여 각각 초기화 콜백, 소멸 전 콜백을 사용할 수 있다.
스프링 전용 인터페이스라 스프링에 의존하며 메서드 이름을 변경 할 수 없다.
내가 수정 할 수 없는 외부 라이브러리에는 적용 할 수 없다.
지금은 거의 안쓴다. 쓰지말자...

2. Bean의 설정 정보에 초기화, 종료 메서드 지정

public class BeanLifeCycleTest {
    @Test
    public void lifecycle() {
        ConfigurableApplicationContext ac = new AnnotationConfigApplicationContext(LifeCycleConfig.class);
        TestBean bean = ac.getBean(TestBean.class);

        ac.close();
    }

    @Configuration
    static class LifeCycleConfig {
        @Bean(initMethod = "init", destroyMethod = "close")
        public TestBean networkClient() {
            TestBean testBean = new TestBean();

            return testBean;
        }
    }
}

@Bean 애너테이션에 initMethod, destroyMethod를 명시해준다.
메서드 이름은 TestBean에 있는 메서드 이름이다.

public class TestBean {

    public TestBean() {
    }

    // 서비스 시작 시 호출
    public void whenServiceStart() {
        System.out.println("TestBean.whenServiceStart");
    }

    //서비스 종료 시 호출
    public void whenServiceDone() {
        System.out.println("TestBean.whenServiceDone");
    }

    public void init() {
        System.out.println("TestBean.init");
        whenServiceStart();
    }

    public void close() {
        System.out.println("TestBean.close");
        whenServiceDone();
    }
}

TestBean 클래스는 평범해진다.

명시된 메서드를 통해 초기화 콜백, 소멸 전 콜백을 사용 할 수 있다.
메서드 이름을 자유롭게 지정할 수 있고 스프링에 의존적이지도 않다.
고칠 수 없는 외부 라이브러리에도 적용 할 수 있다.

@Bean의 distroyMethod는 추론 기능을 제공한다.
라이브러리 대부분이 'close()', 'shutdown()' 이라는 종료 매서드명을 사용하기 때문에 사용자가 따로 이름을 적지 않으면 알아서 찾아서 소멸 전 콜백을 사용한다.

3. @PostConstruct, @PreDestory

public class BeanLifeCycleTest {
    @Test
    public void lifecycle() {
        ConfigurableApplicationContext ac = new AnnotationConfigApplicationContext(LifeCycleConfig.class);
        TestBean bean = ac.getBean(TestBean.class);

        ac.close();
    }

    @Configuration
    static class LifeCycleConfig {
        @Bean
        public TestBean networkClient() {
            TestBean testBean = new TestBean();

            return testBean;
        }
    }
}
public class TestBean {

    public TestBean() {
    }

    // 서비스 시작 시 호출
    public void whenServiceStart() {
        System.out.println("TestBean.whenServiceStart");
    }

    //서비스 종료 시 호출
    public void whenServiceDone() {
        System.out.println("TestBean.whenServiceDone");
    }

    @PostConstruct
    public void init() {
        System.out.println("TestBean.init");
        whenServiceStart();
    }

    @PreDestroy
    public void close() {
        System.out.println("TestBean.close");
        whenServiceDone();
    }
}

TestBean클래스 내부에 @PostConstruct, @PreDestory 어노테이션을 사용하여 초기화 콜백, 소멸 전 콜백을 사용한다.
스프링에서 가장 권장하는 방법이며, 간단하다.
'javax.annotation'을 사용하기 때문에 스프링에 종속적이지 않은 자바 표준이다.
단, 외부 라이브러리에 적용하지 못한다.

결과

결과적으로 @PostConstruct, @PreDestory을 사용하는 것이 가장 좋다.
코드를 고칠 수 없는 외부 라이브러리를 사용한다면 @Bean의 initMethod, destroyMethod을 사용하면 된다.

3가지 방법 모두 아래와 같은 결과를 얻을 수 있다.

참고 : 객채 생성과 초기화는 분리하자.

생성자는 필수 정보(파라미터)를 받고 메로리를 할당해서 객체를 생성하는 일을 한다.
반면에 초기화는 생성된 값들을 활용해서 외부 커넥션을 연결하는 등 무거운 동작을 수행한다.

따라서 생성자가 하는 일과 초기화 작업을 하는 것을 분리하는 것이 유지보수 관점에서 좋다.
물론 단순한 작업은 한번에 하는게 나을 수 있다.

해당 내용는 인프런에서 김영한님의 강의를 참고해서 작성하였다.
강의 진짜 좋았다.

profile
머리에 다 안들어가서 글로 적는 중

0개의 댓글