스프링 빈 생명주기
스프링 빈의 생명주기는 다음과 같다.
스프링 컨테이너 생성 → 스프링 빈 생성 → 의존관계 주입 → 초기화 콜백 → 빈 사용 → 소멸 전 콜백 →스프링 종료
콜백(Callback)은 특정 시점에 시스템이 자동으로 호출하는 메소드다. 스프링에서는 빈을 초기화 하거나 소멸 시점에 개발자가 원하는 작업을 할 수 있도록 콜백 메소드를 제공한다. 초기화는 초기 세팅이나 DB 같은 외부 리소스 연결 등에 사용하고, 소멸은 연결 해제 등에 사용한다.
public class NetworkClient {
private String url;
public NetworkClient() {
System.out.println("생성자 호출, url = " + url);
connect();
call("초기화 연결 메시지");
}
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);
}
}
테스트 코드를 작성한다. NetworkClient는 생성되면서 connect로 연결하고, 소멸 시 disconnect로 해제한다.
public class BeanLifeCycleTest {
@Test
public void lifeCycleTest() {
ConfigurableApplicationContext ac = new AnnotationConfigApplicationContext(LifeCycleConfig.class);
NetworkClient client = ac.getBean(NetworkClient.class);
ac.close();
}
@Configuration
static class LifeCycleConfig {
@Bean
public NetworkClient networkClient() {
NetworkClient networkClient = new NetworkClient();
networkClient.setUrl("https://blog.raphong.com");
return networkClient;
}
}
}
NetworkClinet를 빈으로 등록하면서 생성자 호출 이후 setter를 통해 url을 초기화하도록 했다. 해당 코드를 실행하면 생성자에서 출력하는 3줄이 나오는데, url 변수가 전부 null로 출력된다. 이유는 생성자 호출 이후에 setter를 호출하기 때문이다.
빈 생명주기 콜백의 종류 및 구현 방법은 대표적으로 세가지가 있다.
인터페이스 구현
public class NetworkClient implements InitializingBean, DisposableBean {
...
public NetworkClient() {
System.out.println("생성자 호출, url = " + url);
}
...
@Override //다음부터 init으로 변경
public void afterPropertiesSet() throws Exception {
connect();
call("초기화 연결 메시지");
}
@Override //다음부터 close로 변경
public void destroy() throws Exception {
disConnect();
}
}
InitializingBean
을 상속하면서 afterPropertiesSet() 메소드에 초기화 작업을 구현한다.- 원래 생성자에 있던 connect와 call을 해당 메소드로 옮겼다.
DisposableBean
을 상속하면서 destroy() 메소드에 소멸 작업을 구현한다.- disconnect 메소드를 작성한다.
실행 시 문제 없이 생성자 출력 내용 → 초기화 출력 내용 → 소멸 출력 내용이 나오지만, 해당 방식은 스프링에 의존적이기 때문에 스프링에서만 사용할 수 있고, afterPropertiesSet() 및 destroy() 메소드의 이름을 변경할 수도 없다. 초창기에 사용하던 방식으로 지금은 거의 사용하지 않는다.
@Bean 어노테이션의 속성
public class BeanLifeCycleTest {
...
@Configuration
static class LifeCycleConfig {
@Bean(initMethod = "init", destroyMethod = "close")
public NetworkClient networkClient() {
NetworkClient networkClient = new NetworkClient();
networkClient.setUrl("https://blog.raphong.com");
return networkClient;
}
}
}
@Bean 어노테이션의 속성인 initMethod와 destroyMethod로 생성과 소멸에 사용할 콜백을 지정할 수 있다. 해당 방법은 외부 라이브러리에도 적용 가능하며, 메소드명을 자유롭게 지정할 수 있다. 또한 destroyMethod의 경우 기본적으로 '추론(inferred)'이 들어가게 되는데, 대부분의 라이브러리에서 사용하는 close 또는 shutdown 메소드를 자동으로 호출해준다.
어노테이션
public class NetworkClient {
...
@PostConstruct
public void init() {
System.out.println("NetworkClient.init");
connect();
call("초기화 연결 메시지");
}
@PreDestroy
public void close() {
System.out.println("NetworkClient.close");
disConnect();
}
}
- @PostConstruct 어노테이션을 붙인 메소드는 의존관계 주입이 끝난 후 호출된다.
- @PreDestroy 어노테이션을 붙인 메소드는 빈 소멸 직전에 호출된다.
어노테이션을 붙이면 자동으로 처리되며, 이 방식은 자바 표준(Jakarta EE, JSR-250)으로 스프링에 종속적이지 않아 가장 권장하는 방법이다. 외부 라이브러리에는 사용할 수 없다는 단점이 있다.
'스터디 > Spring' 카테고리의 다른 글
Spring 스터디3 - 1 (1) | 2025.06.10 |
---|---|
Spring 스터디2 - 10 (0) | 2025.05.31 |
Spring 스터디2 - 8 (0) | 2025.05.11 |
Spring 스터디2 - 7 (0) | 2025.04.29 |
Spring 스터디2 - 6 (0) | 2025.04.27 |