안녕세계
[Spring] Bean Life Cycle 본문
[Spring] Bean Life Cycle
Junhong Kim 2025. 1. 5. 19:28Spring Bean은 Spring IoC Container에 의해 관리되는 객체를 의미합니다. Spring IoC Container가 생성, 의존성 주입, 초기화, 사용, 소멸 과정을 책임지게 되는데, 이때 Spring Bean Life Cycle은 다음과 같습니다.
1. 객체 생성: IoC Continaer가 Bean을 생성
2. 의존성 주입: Bean 의존성 주입
3. 초기화: Bean을 사용 가능한 상태로 초기화 작업 실행
4. 사용: 애플리케이션에서 Bean을 사용
5. 소멸: 애플리케이션이 종료되거나 Bean 수명이 끝나면 소멸 작업 실행
1. 객체 생성
Spring IoC Container는 애플리케이션의 Bean 정의에 따라 객체를 생성합니다. Bean 정의 방법은 (1) XML Config, (2) Java Config (@Configuration, @Bean), (3) Annotation (@Component, @Service, @Repository, #Controller) 세 가지 방법이 있습니다. XML 대신 Java Config 또는 Annotation을 활용해서 Bean을 정의하는 것이 보편 적이며, Annotation을 활용해서 Bean 정의하는 방법은 다음과 같습니다.
@Component
public class MyBean {
public MyBean() {
System.out.println("MyBean 객체 생성됨!");
}
}
2. 의존성 주입
Spring IoC Container는 Bean 객체 생성이 완료된 후, 필요한 의존성을 주입합니다. 의존성 주입 방법은 (1) 필드 주입, (2) 생성자 주입 (3) Setter 주입 세가지 방법이 있습니다. 생성자 주입을 통해 의존성을 주입하는 것이 보편 적이며, 생성자 주입 방법은 다음과 같습니다.
@Component
public class MyService {
private final MyRepository repository;
@Autowired
public MyService(MyRepository repository) {
this.repository = repository; // 의존성 주입
}
}
3. 초기화
Bean 의존성 주입이 완료된 후, 초기화 과정을 진행합니다. 초기화 과정을 통해 Bean이 사용 가능한 상태로 전환되며, 초기화 방법은 (1) @PostContruct 사용, (2) InitializingBean 인터페이스의 afterPropertiesSet() 구현, (3) XML/Java Config의 init-method 설정 세 가지 방법이 있습니다.
사실, 본 포스팅을 작성하게 된 이유는 초기화 방법에 대해 정리하고자 함이었습니다.
@PostConstruct와 InitializingBean 인터페이스의 afterPropertiesSet() 구현은 중복해서 사용할 수 있으며, 실행 순서와 기능적 차이가 존재합니다. 앞서 이야기했던 것 처럼 두 방법 모두 초기화 단계에서 실행되는 것을 지원하지만, 실행 순서에 차이가 있습니다. 결론 부터 말하자면 Spring Bean Life Cycle에서 @PostConstruct가 먼저 실행되고, 이후 InitializingBean.afterPropertiesSet()가 실행됩니다.
- @PostConsturct: 의존성 주입이 완료된 후 초기화를 위해 실행
- InitializingBean.afterPropertiesSet(): @PostConstruct 실행 후, 초기화 작업을 추가로 실행
두 초기화 방법을 적용한 Bean 정의는 다음과 같습니다.
@Component
public class MyBean implements InitializingBean {
public MyBean() {
System.out.println("1. 객체 생성");
}
@PostConstruct
public void postConstruct() {
System.out.println("2. @PostConstruct 실행");
}
@Override
public void afterPropertiesSet() {
System.out.println("3. InitializingBean.afterPropertiesSet 실행");
}
}
적용 방법과 실행 시점 외에도 @PostConstruct는 Java 표준 스펙(JSR-250)이고, InitializingBean은 Spring 전용 인터페이스라는 차이점이 있습니다. 따라서, @PostConstruct는 표준 Java 어노테이션이므로 Spring 외 다른 프레임워크(예: Java EE 등)에서도 사용할 수 있지만, InitializingBean은 Spring 프레임워크에 종속 됩니다. 참고로, InitializingBean은 주로 레거시 코드에서 사용되고 최근 코드에서는 잘 사용되지 합니다. 즉, @PostConstruct는 표준화된 방식이고, InitializingBean은 Spring에 종속적입니다.
한 가지 더 알아 둘 점은 @PostConstruct는 JSR-250에 정의된 표준 Java 어노테이션이므로 Spring 외의 다른 JSR-250을 지원하는 프레임워크에서도 사용할 수 있습니다. 하지만 순수한 Java 객체나 Spring 외부의 환경에서는 자동으로 동작하지 않습니다. 이를 제대로 동작시키려면 컨테이너나 프레임워크가 @PostConstruct를 처리할 수 있도록 지원해야 합니다.
@PostConstruct는 다음 환경에서 동작합니다.
1. JSR-250을 지원하는 프레임워크나 컨테이너가 존재해야 합니다. (Spring, Java EE 등)
2. 컨테이너가 객체를 관리하고 있어야 합니다.
순수한 Java 환경에서 @PostConstruct를 사용하려면, 이를 수동으로 호출하는 코드를 작성해야 합니다. Spring 없이 순수 Java로 작성하면, 컨테이너가 없기 때문에 직접 호출 로직이 필요합니다.
import javax.annotation.PostConstruct;
public class MyBean {
@PostConstruct
public void init() {
System.out.println("PostConstruct 초기화 작업 실행");
}
public static void main(String[] args) throws Exception {
MyBean myBean = new MyBean();
// 수동으로 @PostConstruct 메서드 호출
for (var method : myBean.getClass().getMethods()) {
if (method.isAnnotationPresent(PostConstruct.class)) {
method.invoke(myBean); // @PostConstruct 실행
}
}
}
}
따라서, 순수 Java 환경에서 @PostConstruct를 사용하지 않고, 초기화 작업을 수행하는 방법은 (1) 생성자를 사용하거나 (2) 초기화 메서드를 호출하는 대안이 있습니다.
생성자 사용
public class MyBean {
public MyBean() {
System.out.println("초기화 작업 실행");
}
}
초기화 메서드 사용
public class MyBean {
public void init() {
System.out.println("초기화 작업 실행");
}
public static void main(String[] args) {
MyBean myBean = new MyBean();
myBean.init(); // 초기화 작업 수동 호출
}
}
4. 사용
초기화가 완료된 Bean은 애플리케이션 내에서 사용됩니다. 이 단계는 애플리케이션이 실행되면서 Bean이 실제로 사용되는 부분입니다.
@RestController
public class MyController {
private final MyService myService;
@Autowired
public MyController(MyService myService) {
this.myService = myService;
}
@GetMapping("/hello")
public String sayHello() {
return "Hello, Spring Bean!";
}
}
5. 소멸
Bean이 더 이상 필요 없거나 IoC Container가 종료될 때 소멸 작업이 수행됩니다. 이때, 소멸 작업을 정의하기 위해 @PreDestroy 또는 DisposableBean 인터페이스를 사용합니다. 두 방법은 앞서 살펴본 @PostConsturct와 InitializingBean.afterPropertiesSet() 구현하는 것과 대응됩니다. @PreDestroy는 JSR-250 표준이고 컨테이너 종료시 호출되며, DisposableBean.destroy()는 Spring 전용 인터페이스이고 @PreDestroy 이후에 호출됩니다. 두 방법을 적용한 예시는 다음과 같습니다.
@Component
public class MyFullBean implements DisposableBean {
@PreDestroy
public void preDestroyMethod() {
System.out.println("1. @PreDestroy 실행");
}
@Override
public void destroy() {
System.out.println("2. DisposableBean.destroy 실행");
}
}
전체 Life Cycle 흐름
Bean Life Cycle을 하나의 Bean 모두 적용했을 때의 순서와 방법은 다음을 참고해주세요.
@Component
public class MyFullBean implements InitializingBean, DisposableBean {
// 객체 생성 시 호출되는 초기화 블록
public MyFullBean() {
System.out.println("1. 객체 생성");
}
// @PostConstruct 어노테이션: 초기화 작업 수행
@PostConstruct
public void postConstruct() {
System.out.println("2. @PostConstruct 실행");
}
// InitializingBean 인터페이스: 추가 초기화 작업
@Override
public void afterPropertiesSet() {
System.out.println("3. InitializingBean.afterPropertiesSet 실행");
}
// @PreDestroy 어노테이션: 소멸 작업 수행
@PreDestroy
public void preDestroy() {
System.out.println("4. @PreDestroy 실행");
}
// DisposableBean 인터페이스: 추가 소멸 작업
@Override
public void destroy() {
System.out.println("5. DisposableBean.destroy 실행");
}
}
참고
https://www.geeksforgeeks.org/bean-life-cycle-in-java-spring/
'Server > Spring' 카테고리의 다른 글
[Spring] @PostPersist와 TransactionPhase.AFTER_COMMIT (0) | 2024.06.30 |
---|---|
[Spring] SSE란? (feat. SseEmitter) (0) | 2024.03.03 |
[Spring] JPA 성능 최적화 (0) | 2023.05.06 |
[Spring] 그라파나와 로키로 애플리케이션 로그 조회하기 (0) | 2023.04.22 |
[Spring] 그라파나와 프로메테우스로 애플리케이션 모니터링하기 (1) | 2023.04.09 |