본 내용은 인프런의 김영한 님의 강의 "스프링 핵심 원리 - 기본편" 내용을 바탕으로 정리한 내용입니다.
스프링 프레임워크에서 빈의 생명주기란?
해당 빈이 생성되고 초기화되는 과정부터 소멸되는 과정까지를 말한다. 스프링은 빈의 생명주기를 관리하기 위해 빈의 생성, 초기화, 사용, 소멸에 대한 콜백 메서드를 제공하는데 이러한 콜백 메서드를 사용하여 빈이 특정 시점에 어떤 동작을 수행하도록 할 수 있다.
스프링 빈의 싱글톤 이벤트 라이프 사이클
스프링 컨테이너 생성 > 스프링 빈 생성 > 의존관계 주입 > 초기화 콜백 사용 > 소멸전 콜백 > 스프링 종료
초기화 콜백
- 빈이 생성되고, 의존성 주입이 완료된 후에 호출되는 메서드를 의미한다.
- 초기화 콜백을 사용하여 빈은 초기화 작업을 수행할 수 있으며, 데이터베이스 연결, 리소스 로딩, 외부 서비스 초기화 등의 작업을 처리할 수 있다.
- ex) InitializingBean 인터페이스, @PostConstruct 어노테이션
소멸 전 콜백
- 빈이 스프링 컨테이너에서 소멸되기 직전에 호출되는 메서드를 의미한다.
- 싱글톤 빈들은 스프링 컨테이너가 종료될 때 싱글톤 빈들도 함께 종료되기 때문에 스프링 컨테이너가 종료되기 직전에 소멸전 콜백이 일어난다.
- ex) DisposableBean 인터페이스, @PreDestroy 어노테이션
※ 참고 : 객체의 생성과 초기화를 분리하자!!!
생성자는 필수 정보를 받아 객체를 생성하는 책임을 가지고, 초기화는 생성된 값들을 활용해 외부 커넥션을 연결하는 등 무거운 동작을 수행한다. 따라서 두 부분을 분리하는 것이 유지보수 관점에서 좋다. 물론 초기화 작업이 간단하면 생성자에서 한번에 다 처리할 수도 있다.
InitializingBean 인터페이스 / DisposableBean 인터페이스
- InitializingBean 인터페이스를 구현하여 afterPropertiesSet() 메서드를 오버라이드하면 의존성 주입이 완료된 후 이 메서드가 호출된다.
- DisposableBean 인터페이스를 구현하여 destroy() 메서드를 오버라이드하면 빈이 소멸되기 직전에 이 메서드가 호출된다.
예시)
@Configuration
public class AppConfig {
@Bean
public SpringBean springBean() {
SpringBean springBean = new SpringBean();
springBean.setName("springBean");
return springBean;
}
}
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
public class SpringBean implements InitializingBean, DisposableBean {
private String name;
public SpringBean() {
// 기본 생성자
}
public SpringBean(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// InitializingBean 인터페이스의 메서드 구현
@Override
public void afterPropertiesSet() throws Exception {
// 빈 초기화 시 호출되는 메서드
System.out.println("SpringBean is being initialized. Name: " + name);
// 이 곳에서 원하는 초기화 작업을 수행할 수 있다.
connect();
}
// DisposableBean 인터페이스의 메서드 구현
@Override
public void destroy() throws Exception {
// 빈 소멸 시 호출되는 메서드
System.out.println("SpringBean is being destroyed. Name: " + name);
// 이 곳에서 원하는 종료 작업을 수행할 수 있다.
disconnect();
}
// 초기화 작업을 위한 사용자 정의 메서드
public void connect() {
System.out.println("Connecting to external resource. Name: " + name);
// 외부 리소스와의 연결 설정을 수행한다.
}
// 종료 작업을 위한 사용자 정의 메서드
public void disconnect() {
System.out.println("Disconnecting from external resource. Name: " + name);
// 외부 리소스와의 연결 해제를 수행한다.
}
}
@PostConstruct 어노테이션 / @PreDestroy 어노테이션
- @PostConstruct를 초기화 메서드에 붙이면 해당 메서드는 빈의 의존성 주입이 완료된 후 자동으로 호출된다.
- @PreDestroy을 소멸 메서드에 붙이면 해당 메서드는 빈이 소멸되기 직전에 자동으로 호출된다.
- 최신 스프링에서 권장하는 방식이다.
- 스프링에 종속적인 기술이 아니라 다른 컨테이너에서도 사용가능하다.
예시)
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class SpringBean {
private String name;
public SpringBean() {
// 기본 생성자
}
public SpringBean(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// @PostConstruct 어노테이션을 이용한 초기화 메서드
@PostConstruct
public void init() {
// 빈 초기화 시 호출되는 메서드
System.out.println("SpringBean is being initialized. Name: " + name);
// 이 곳에서 원하는 초기화 작업을 수행할 수 있다.
connect();
}
// @PreDestroy 어노테이션을 이용한 소멸 메서드
@PreDestroy
public void destroy() {
// 빈 소멸 시 호출되는 메서드
System.out.println("SpringBean is being destroyed. Name: " + name);
// 이 곳에서 원하는 종료 작업을 수행할 수 있다.
disconnect();
}
// 초기화 작업을 위한 사용자 정의 메서드
public void connect() {
System.out.println("Connecting to external resource. Name: " + name);
// 외부 리소스와의 연결 설정을 수행한다.
}
// 종료 작업을 위한 사용자 정의 메서드
public void disconnect() {
System.out.println("Disconnecting from external resource. Name: " + name);
// 외부 리소스와의 연결 해제를 수행한다.
}
}
@PostConstruct / @PreDestroy의 장점
1. 유연성
@PostConstruct와 @PreDestroy 어노테이션은 인터페이스를 구현하는 것과 달리, 어떤 클래스에든 어노테이션을 적용하여 초기화와 소멸 메서드를 정의할 수 있다. 따라서 인터페이스에 종속되지 않으며, 다른 인터페이스를 구현해야 하는 경우에도 자유롭게 사용할 수 있다.
2. 인터페이스 구현 회피
InitializingBean과 DisposableBean 인터페이스를 구현하는 방법은 클래스가 스프링에 의존하게 되므로, 클래스의 코드가 스프링 프레임워크에 의해 영향을 받을 수 있다. 반면 어노테이션을 사용하면 클래스에 스프링 종속성이 추가되지 않으므로, 코드의 유지보수와 테스트가 더욱 용이해진다.
3. 코드 가독성
어노테이션을 사용하면 빈의 초기화와 소멸 콜백 메서드가 클래스의 일반적인 메서드와 동일한 위치에 있어 가독성이 높아진다. 인터페이스 구현 방식은 해당 인터페이스의 메서드를 따로 구현해야 하기 때문에 가독성이 낮다.
4. 여러 초기화/소멸 메서드 지원
@PostConstruct와 @PreDestroy 어노테이션은 한 클래스에 여러 개의 초기화와 소멸 메서드를 정의할 수 있다. 반면 인터페이스 구현은 각각의 인터페이스에 하나의 초기화와 소멸 메서드를 정의해야 한다.
'Spring' 카테고리의 다른 글
[스프링] 로그 추적기 (0) | 2024.05.04 |
---|---|
[스프링] 빈 스코프란? (0) | 2023.07.23 |
[스프링] 스프링 빈의 자동 주입과 수동 주입 (0) | 2023.07.22 |
[스프링] 커스텀 어노테이션(Custom Annotation) (0) | 2023.07.22 |
[스프링] 조회할 빈이 2개 이상일 경우(@Qualifier, @Primary) (0) | 2023.07.22 |