해당 내용은 김영한씨의 강의 및 스프링 프레임워크 공식 문서, 공식문서 번역을 참고하여 작성한 글입니다.
올바르지 않은 내용이 있다면 의견 남겨주세요. 언제든지 환영입니다.
1. Lifecycle Callbacks
데이터베이스 커넥션 풀이나, 네트워크 소켓처럼 애플리케이션 시작 시점에 필요한 연결을 미리 해두고, 애플리케이션 종료 시점에 연결을 모두 종료하는 작업을 진행하려면, 객체의 초기화와 종료 작업이 필요하다.
아래는 김영한씨의 강의의 예제 코드를 참고하여 우리가 의도하는 결과가 나오는지 테스트해보았다.
public class NetworkClientTest {
private String url;
public NetworkClientTest() {
System.out.println("현재 url은 다음과 같습니다 : " + url);
connect();
call("초기화 연결되었습니다");
}
// 연결함수
public void connect() {
System.out.println("connect, 연결된 url : " + url);
}
public void disconnect() {
System.out.println("disconnect, 연결 끊어버린 url : " + url);
}
// URL 세팅 함수
public void setUrl(String url) {
this.url = url;
}
// 호출함수
// @param msg : 호출하려는 메세지
public void call(String msg) {
System.out.println("call message : " + msg + " url : " + url);
}
}
나는 객체가 생성되면서, 원하는 url이 세팅되도록 의도했으나 그게 되지 않았다. 당연하다. 스프링 빈은 객체를 생성할 때 생성자 > 세터기반으로 생성하고 그 뒤에 의존관계를 주입한다. 이미 저 코드는 주입까지 모두 마친 후에 내가 초기값을 할당한게 된다. 그럼 connect() 함수가 실행 되기 전, 초기값을 세팅하고 싶으면 어떻게 해야할까? 방법은 아래 3가지로 나타낼 수 있다.
2. InitializingBean, DisposableBean
InitializingBean, DisposableBean 인터페이스들로 초기화 작업 및 연결을 끊은 이후의 작업을 진행할 수 있다.
public class NetworkClientTest implements InitializingBean, DisposableBean {
private String url;
public NetworkClientTest() {
System.out.println("현재 url은 다음과 같습니다 : " + url);
}
// 연결함수
public void connect() {
System.out.println("connect, 연결된 url : " + url);
}
public void disconnect() {
System.out.println("disconnect, 연결 끊어버린 url : " + url);
}
// URL 세팅 함수
public void setUrl(String url) {
this.url = url;
}
// 호출함수
// @param msg : 호출하려는 메세지
public void call(String msg) {
System.out.println("call message : " + msg + " url : " + url);
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet, 초기화 작업 함수");
connect();
call("초기화 연결되었습니다");
}
@Override
public void destroy() throws Exception {
System.out.println("destroy, 연결 파괴될 때 callback");
}
}
다만, 위의 인터페이스들은 스프링 전용 인터페이스이며 스프링 공식문서에서는 JSR-250의 @PostConstruct @PreDestroy을 사용하길 권장한다. 해당 @은 스프링 전용 인터페이스가 아니고 자바 표준이며 스프링이 아닌 다른 컨테이너에서도 동작하기 때문이다.
3. @PostConstruct @PreDestroy
public class NetworkClientTest{
private String url;
public NetworkClientTest() {
System.out.println("현재 url은 다음과 같습니다 : " + url);
}
// 연결함수
public void connect() {
System.out.println("connect, 연결된 url : " + url);
}
public void disconnect() {
System.out.println("disconnect, 연결 끊어버린 url : " + url);
}
// URL 세팅 함수
public void setUrl(String url) {
this.url = url;
}
// 호출함수
// @param msg : 호출하려는 메세지
public void call(String msg) {
System.out.println("call message : " + msg + " url : " + url);
}
@PostConstruct
public void init() throws Exception {
System.out.println("PostConstruct 초기화 작업 함수");
connect();
call("초기화 연결되었습니다");
}
@PreDestroy
public void close() throws Exception {
System.out.println("PreDestroy, 연결 파괴될 때 callback");
}
}
@PostConstruct, @PreDestroy가 붙은 메서드는 명시적으로 선언된 callback 메서드와 생명주기의 같은 지점에서 호출된다. @만 붙이면 되므로 매우 편리한 장점을 가지고 있다. 다만 외부 라이브러리에는 적용하지 못하므로, 외부 라이브러리를 초기화, 종료해야한다면 @Bean의 기능을 사용한다.
4. Receiving Lifecycle Callbacks
public class NetworkClientTest{
private String url;
public NetworkClientTest() {
System.out.println("현재 url은 다음과 같습니다 : " + url);
}
// 연결함수
public void connect() {
System.out.println("connect, 연결된 url : " + url);
}
public void disconnect() {
System.out.println("disconnect, 연결 끊어버린 url : " + url);
}
// URL 세팅 함수
public void setUrl(String url) {
this.url = url;
}
// 호출함수
// @param msg : 호출하려는 메세지
public void call(String msg) {
System.out.println("call message : " + msg + " url : " + url);
}
public void init() throws Exception {
System.out.println("init 초기화 작업 함수");
connect();
call("초기화 연결되었습니다");
}
public void close() throws Exception {
System.out.println("PreDestroy, 연결 파괴될 때 callback");
}
}
@Bean을 통해 정의된 모든 클래스는 일반적인 생명주기 콜백을 지원한다. @Bean은 Spring XML의 bean 엘리먼트 속성인 init-method, destroy-method에 초기화, 파괴용도의 콜백 메서드를 지정할 수 있다. 만약, 기본적으로 'close', 'shoutdown'이라는 이름을 가진 public 메서드를 갖고 있다면 자동적으로 콜백에 참여하게 된다. 호출하기를 원하지 않는다면 @Bean(destroyMethod="") 와 같이 추가한다. @Bean은 기본적으로 (inferred, 추론) 하기 때문이다.
5. Combining Lifecycle Mechanisms
빈(Bean) 생명주기 동작 방법을 3가지를 알아보았다. 만약 하나의 빈에 여러개의 생명주기 동작이 설정되었고, 각기 다른 메서드 이름으로 구성되었을 때 각 메서드는 다음과 같은 순서로 실행된다.
만일 중복된 메서드 이름이 존재한다면 한번만 실행된다.
Initialization methods | Destroy methods |
1. @PostConstruct 2. InitializingBean 인터페이스에서 정의된 afterPropertiesSet() 3. 커스텀한 init() |
1. @PreDestroy 2. DisposableBean 인터페이스에서 정의된 destroy() 3. 커스텀한 destroy() |
참고 1) 김영한(스프링 핵심원리 - 기본편)
Core Technologies
In the preceding scenario, using @Autowired works well and provides the desired modularity, but determining exactly where the autowired bean definitions are declared is still somewhat ambiguous. For example, as a developer looking at ServiceConfig, how do
docs.spring.io
Spring Core Technologies - 1.12. Java-based Container Configuration
johngrib.github.io
'Java > Spring' 카테고리의 다른 글
[Spring] MVC 발전과정(2) (0) | 2024.10.31 |
---|---|
[Spring] MVC 발전과정(1) (0) | 2024.10.30 |
[Spring] Singleton (0) | 2023.02.03 |
[Spring] IOC (0) | 2023.01.26 |
[Spring] DI (0) | 2023.01.23 |