🌱 김영한님의 스프링 핵심 원리 - 기본편을 수강한 후 학습한 내용을 정리하고 기록하기 위해 작성하는 포스팅입니다.
스프링 빈의 이벤트 생명주기
스프링 빈은 위와 같은 이벤트 라이프사이클을 가진다. 위의 흐름에 따르면 의존관계 주입이 끝난 후에 초기화 작업을 해줘야하는데, 애플리케이션 입장에서 의존관계 주입이 끝난지를 어떻게 알 수 있을까? 그 답은 생명주기 콜백이다!
자바스크립트에서 어떤 이벤트가 끝난 시점에 다른 로직을 수행해줘야할 때 사용했던 콜백에 대해 아마 대부분 익숙할거다. 이처럼 스프링에서도 빈 생명주기 콜백을 이용해 특정 생명주기 시점에 어떤 메서드가 동작할 수 있도록 지원해주고 있다.
cf. 빈 생성 단계에 생성자에서 초기화를 해주면 되지 않을까?
초기화 단계와 빈 생성 단계는 분리해주는게 좋다. 생성 단계에서는 최소한의 필수 정보를 받아서객체를 생성하는 책임
만을 다하고, 초기화 단계에 이렇게 생성된 객체를 활용해서 외부 커넥션을 연결하는 등 무거운 동작을 수행해주는 것이 단일 책임 원칙에도 맞다. 이를 합쳐서 생성자에서 수행할 경우, 유지보수가 힘들어질 수 있다.
또 초기화와 생성 단계를 구분해주면, 최초의 동작이 있을 때까지 미뤘다가 초기화를 수행해줄 수 있기 때문에, 이로부터 장점을 얻을 수 있는 경우도 간혹 있다.
생명주기 콜백은 크게 초기화 콜백
과 소멸 전 콜백
으로 나뉘어지고, 이를 지원하는 방식에는 크게 3가지가 있다.
InitializingBean
, DisposableBean
인터페이스
-> 단점: 코드가 스프링에 의존적이다. 따라서 내가 코드를 고칠 수 없는 외부 라이브러리에 적용이 불가능해서 거의 사용하지 않는다.
자체 메서드 활용
-> 자체 메서드를 활용하고(이름도 상관없고, 어노테이션을 붙일 필요도 없다) 초기화 및 종료 메서드를 initMethod, destroyMethod로 설정해주는 방식이다.
@Configuration
static class LifeCycleConfig {
@Bean(initMethod = "init", destroyMethod = "close")
public NetworkClient networkClient(){
NetworkClient networkClient = new NetworkClient(); // 빈 생성 단계는 이 줄에서 끝남
networkClient.setUrl("http://hello-spring.dev");
return networkClient;
}
}
한편 destroyMethod는 기본값이 inferred(추론)이라서, close()나 shutdown()이라는 이름의 메서드가 있으면 자동으로 해당 메서드가 종료 메서드로 등록이 된다.(그래서 외부 라이브러리들도 보통 종료 메서드 이름을 close(), shutdown()으로 지정해둔다 / 공백("")으로 두면 아무 메서드도 동작하지 않을 수 있다)
-> 실제 클래스 밖에서 설정이 가능하기 때문에, 외부 라이브러리의 경우에도 자유롭게 사용할 수 있다는 장점이 있다.
@PostConstruct
, @PreDestroy
어노테이션