(인프런) 김영한님의 스프링 핵심 원리-기본편을 공부하고 리뷰한 글입니다.
<스프링 빈 생명주기 콜백 지원 방법>
1) 인터페이스(InitializingBean, DisposableBean)
2) 설정 정보에 초기화 메서드, 종료 메서드 지정
3) @PostConstruct, @PreDestroy 애노테이션 지원
4. 애노테이션 @PostConstruct, @PreDestroy
1. NetworkClient 코드 수정
1) @PostConstruct : 초기화 메서드 앞에 추가
2) @PreDestroy : 소멸 메서드 앞에 추가
package hello.core.lifecycle;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
// 가상 네트워크 클라이언트
public class NetworkClient {
private String url; // 접속해야할 서버 url
// 디폴트 생성자
public NetworkClient() {
System.out.println("생성자를 호출, url = " + 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();
}
}
2. LifeCycleConfig 코드 수정
@Bean의 속성을 지정하지 않고 그냥 수동 빈 등록을 하면 된다.
public class BeanLifeCycleTest {
...
@Configuration
static class LifeCycleConfig {
// NetworkClient 수동 빈 등록
@Bean
public NetworkClient networkClient() {
NetworkClient networkClient = new NetworkClient();
networkClient.setUrl("http://hello-spring.dev"); // 연결할 서버 url 설정
return networkClient;
}
}
}
3. 실행 결과
4. @PostConstruct, @PreDestory 애노테이션 특징
- 최신 스프링에서 가장 권장하는 방법이다.
- 애노테이션 하나만 붙이면 되므로 매우 편리하다.
- javax.annotation.PostConstruct 패키지는 스프링에 종속적인 기술이 아니라 JSR-250이라는 자바 표준이기 떄문에 스프링이 아닌 다른 컨테이너에서도 동작한다.
- 컴포넌트 스캔과 잘 어울린다.
- 유일한 단점은 외부 라이브러리에는 적용하지 못한다는 것이다.
<정리>
1) 기본적으로 @PostConstruct, @PreDestroy 애노테이션을 사용하자
2) 코드를 고칠 수 없는 외부 라이브러리를 초기화, 종료해야 하면 @Bean 의 initMethod, destroyMethod 를 사용하자.
8-4. 애노테이션 @PostConstruct, @PreDestroy 질문 정리
Q. 스프링 빈과 스프링 컨테이너는 JVM의 heap 영역에 생성되는가? 그렇다면, GC의 대상이 되는가?
A. 스프링 빈과 스프링 컨테이너 역시 객체이므로 heap 영역에 생성되지만 GC의 대상은 아니다.
GC(Garbage Collection)의 대상이 되려면 참조하는 포인터가 없어야 하는데, 싱글톤 빈을 스프링 컨테이너가 참조하고 있다. 스프링 컨테이너도 나의 애플리케이션을 포함한 어디선가 참조하고 있기 때문에 종료직전까지 사라지지 않는다.
[출처] https://www.inflearn.com/questions/95765
Q. 컴포넌트 스캔을 통한 자동 빈 등록시에도 @PostConstruct, @PreDestory 를 사용할 수 있는가?, 만약 그렇다면 기본 설정을 어디서 해야하는가?
A. 자동 빈 등록, 수동 빈 등록 모두 @PostConstructor, @PreDestory 를 사용할 수 있다.
빈 생성 후 별도의 초기화 작업을 하려면 @PostConstrcut를 이용하거나,
빈을 생성할 떄 생성자의 파라미터로 url을 넘기거나, 생성한 이후 별도의 메서드를 호출하여 상태를 변경한다.
(기존) 수동 빈 등록 방식
위 코드를 보면 networkClient 빈을 등록할 때, 생성자로 객체를 생성하고 setUrl()을 통해 url을 설정후 해당 객체를 스프링 빈으로 등록했다.
(변경) 자동 빈 등록 방식
package hello.core.lifecycle;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
// 가상 네트워크 클라이언트
@Component
public class NetworkClient {
private String url; // 접속해야할 서버 url
// 디폴트 생성자
public NetworkClient() {
System.out.println("생성자를 호출, url = " + url);
}
...
// 초기화 메서드(의존관계 주입이 끝나면 호출)
@PostConstruct
public void init() {
System.out.println("NetworkClient.init");
setUrl("http://hello-spring.dev"); // 연결할 서버 url 설정
connect();
call("초기화 연결 메시지");
}
// 소멸 메서드(빈이 종료될 때 호출)
@PreDestroy
public void close(){
System.out.println("NetworkClient.close");
disConnect();
}
}
1) 컴포넌트 스캔을 사용하기 위해 NetworkClient 클래스 앞에 @Component 애노테이션을 추가한다.
2) @PostConstruct 가 붙은 초기화 메서드에서 setUrl()을 호출한다.
@Configuration
@ComponentScan
static class LifeCycleConfig {
}
1) LifeCycleConfig 클래스 내용을 모두 지우고 @ComponentScan 애노테이션을 추가한다.
아래와 같이, 이전과 동일한 출력 결과를 확인할 수 있다.
[참고] https://www.inflearn.com/questions/446872
'Spring > 스프링 핵심 원리 - 기본편' 카테고리의 다른 글
[스프링 핵심 원리] 09. 빈 스코프 - 프로토타입 스코프(싱글톤 빈과 함께 사용시 문제점) (0) | 2022.05.23 |
---|---|
[스프링 핵심 원리] 9. 빈 스코프 - 빈 스코프란? & 프로토타입 스코프 (0) | 2022.05.23 |
[스프링 핵심 원리] 08. 빈 생명주기 콜백 - 빈 등록 초기화, 소멸 메서드 지정 (0) | 2022.05.20 |
[스프링 핵심 원리] 08. 빈 생명주기 콜백 - 인터페이스 InitializingBean, DisposableBean (0) | 2022.05.20 |
[스프링 핵심 원리] 08. 빈 생명주기 콜백 - 빈 생명주기 콜백 시작 (0) | 2022.05.20 |