-
빈 생명주기 콜백스프링/스프링 핵심 원리 - 기본편 2024. 1. 3. 21:23
빈 생명주기의 필요성
- 어플리케이션이 시작될 때 DB 연결, 네트워크 소켓 연결 등을 하고 어플리케이션의 종료 시점에 연결을 종료 해야하는 경우에 객체의 초기화 및 종료 작업을 해야한다.
빈 생명주기의 순서
- 스프링 컨테이너 생성
- 스프링 빈 생성
- 의존관계 주입
- 초기화 콜백
- 사용
- 소멸전 콜백
- 스프링 종료
이러한 순서로 진행되고
콜백방법
- 인터페이스(InitializingBean, DisposableBean)
- 설정 정보에 초기화 메서드, 종료 메서드 지정
- @PostConstruct, @PreDestory 애노테이션 지원
1. 인터페이스의 경우
인터페이스의 사용 예시
package hello.core.lifecycle; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; public class NetworkClient implements InitializingBean, DisposableBean { 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 message) { System.out.println("call: " + url + " message = " + message); } //서비스 종료시 호출 public void disConnect() { System.out.println("close + " + url); } @Override public void afterPropertiesSet() throws Exception { connect(); call("초기화 연결 메시지"); } @Override public void destroy() throws Exception { disConnect(); } }
- InitializingBean은 afterPropertiesSet() 메서드로 초기화를 지원한다.
- DisposableBean은 destroy() 메서드로 소멸을 지원한다.
2. 설정 정보에 초기화 메서드, 종료 메서드 지정
설정 정보에 @Bean(initMethod = "init", destroyMethod = "close") 처럼 초기화, 소멸 메시더를 지정할 수 있다.
설정 정보를 사용하도록 변경된 예시
package hello.core.lifecycle; 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 message) { System.out.println("call: " + url + " message = " + message); } //서비스 종료시 호출 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(); } }
설정 정보에 초기화 소멸 메서드 지정
@Configuration static class LifeCycleConfig { @Bean(initMethod = "init", destroyMethod = "close") public NetworkClient networkClient() { NetworkClient networkClient = new NetworkClient(); networkClient.setUrl("http://hello-spring.dev"); return networkClient; } }
설정 정보 사용 특징
- 메서드 이름을 자유롭게 줄 수 있다.
- 스프링 빈이 스프링 코드에 의존하지 않는다.
- 코드가 아니라 설정 정보를 사용하기 때문에 코드를 고칠 수 없는 외부 라이브러리에도 초기화, 종료 메서드를 적용할 수 있다.
종료 메서드 추론
- @Bean의 destoryMethod 속성에는 아주 특별한 기능이 있다.
- 라이브러리의 대부분 clost, shutdown 이라는 이름의 종료 메서드를 사용한다.
- @Bean의 destoryMethod의 기본값이 (inferred)(추론)으로 등록되어 있다.
- 이 추론 기능은 close, shutdown 라는 이름의 메서드를 자동으로 호출해준다. 이름 그대로 종료 메서드를 추론해서 호출해준다.
- 따라서 직접 스프링 빈으로 등록하면 종료 메서드는 따로 적우지 않아도 잘 동작한다.
- 추론 기능을 사용하기 싫으면 destoryMethod = "" 처럼 빈 공백을 지정하면 된다.
3. 애노테이션 @PostConstruct, @PreDestory
애노테이션 @PostConstruct, @PreDestory 사용 예시
package hello.core.lifecycle; import javax.annotation.PostConstruct; import javax.annotation.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 message) { System.out.println("call: " + url + " message = " + message); } //서비스 종료시 호출 public void disConnect() { System.out.println("close + " + url); } @PostConstruct public void init() { System.out.println("NetworkClient.init"); connect(); call("초기화 연결 메시지"); } @PreDestroy public void close() { System.out.println("NetworkClient.close"); disConnect(); } }
@Configuration static class LifeCycleConfig { @Bean public NetworkClient networkClient() { NetworkClient networkClient = new NetworkClient(); networkClient.setUrl("http://hello-spring.dev"); return networkClient; } }
@PostConstruct, @PreDestory 이 두 애노테이션을 사용하면 가장 편리하게 초기화와 종료를 실행할 수 있다.
@PostConstruct, @PreDestory 애노테이션의 특징
- 최신 스프링에서 가장 권장하는 방법이다.
- 애노테이션 하나만 붙이면 되므로 편리하다.
- 패키지를 잘보면 javax.annotation.PostConstruct 이다. 스프링에 종속적인 기술이 아니라 JSR-250이라는
자바 표준이다. 따라서 스프링이 아닌 다른 컨테이너에서도 동작한다. - 컴포넌트 스캔과 잘 어울린다.
- 유일한 단점은 외부 라이브러리에는 적용하지 못한다는 것이다. 외부 라이브러리를 초기화, 종료 해야 하면
@Bean의 기능을 사용하자.
결론
- @PostConstruct, @PreDestory 애노테이션을 사용하자
- 코드를 고칠 수 없는 외부 라이브러리를 초기화, 종료해야하면 @Bean의 initMethod, destoryMethod를 사용하자.