0. 개요
- 실제로 Web App을 운영하면 App 실행 전에 Server는 미리 DB와 연결해두고, 일정량의 Data를 로드해놓는다.
- 더불어 종료 시점에는 모든 작업을 종료하는 과정에서 객체의 초기화와 종료 작업을 필요로 한다.
- 이처럼 운영하는 이유는, 최초에 App을 실행했을 때 Client의 요청에 빠르게 응답하기 위함이다.
- 이 과정을 구현하기 위해 필요한 Spring Bean의 초기화와 종료 과정을 알아보자.
1. Spring Bean의 생명주기
- 최초에 App이 빌드되는 과정에서, Spring Bean은 객체의 생성을 통해 Spring Container에 등록된 후 의존관계를 형성(주입)한다.
- 이 준비가 완료되어야 Bean을 이용해 다양한 data를 주고받을 수 있다.
- 그러므로 초기화 작업은 의존관계가 형성된 후에 수행되어야 한다.
- 그렇다면 개발자는 이 초기화 작업을 수행하는 시점을 어떻게 알 수 있을까?
a) Lifecycle
- Bean이 형성되고 종료될 때까지의 모든 과정을 생명주기라고 한다.
- 기본적인 Bean의 생명주기는 다음과 같은 과정을 거친다.
Continer 생성 → Bean 등록 → DI 주입 → 초기화 → Bean 사용 → 소멸 → Spring 종료
b) Bean 생성과 초기화 작업을 분리하는 이유
- 생성자 주입을 호출하여 객체의 생성과 초기화를 함께 하도록 하면 되지 않을까?라고 생각할 수 있다.
- 이 경우 생성자는 객체를 생성과 객체의 초기화를 책임지고 있으므로, 이는 SOLID의 SRP에 위배된다.
- 단순히 객체의 내부 값만을 초기화하는 작업이라면, 생성자에서 한 번에 처리하는 것이 효율적일 수 있다.
- 그러나, Spring Bean은 여러 객체 간의 유기적인 연결을 생성하므로 초기화 작업이 단순하지 않다.
- 이와 같은 이유로 Bean의 생성과 초기화를 분리한다.
2. Bean 생명주기 callback
- Spring은 Bean의 초기화와 소멸 시점에서 사용할 수 있는 callback 함수를 제공한다.
- 즉, callback 함수는 Spring에 의해 특정 시점에서 호출되는 함수다.
a) Bean 생명주기 callback의 종류
- Spring은 크게 3가지 방법의 생명주기 callback을 지원한다.
→ InitializingBean, DisposableBean 인터페이스를 이용한 방법
→ 설정 정보에 초기화/종료 메서드를 지정하는 방법
→ @PostConstruct(초기화), @PreDestroy(소멸) 어노테이션을 이용한 방법
3. InitializingBean, DisposableBean
a) InitializingBean
- DI 주입이 완료된 시점에서 사용할 수 있는 메서드를 제공하는 인터페이스
- afterPropertySet() 메서드를 Override 하여 초기화 시점에서 수행할 작업을 명시할 수 있다.
- Bean 생성 및 DI 주입이 완료된 시점에서 Spring에 의해 자동호출(callback)된다.
b) DisposableBean
- Bean 소멸 시 사용할 수 있는 메서드를 제공하는 인터페이스
- destroy() 메서드를 Override 하여 Bean 소멸 시점에서 수행할 작업을 명시할 수 있다.
- Bean의 소멸 시점에서 Spring에 의해 자동호출(callback)된다.
c) InitializingBean, DisposableBean 사용의 단점
- 해당 인터페이스는 모두 Spring에서만 사용할 수 있는, Spring 전용 인터페이스다.
- 그러므로 외부 라이브러리에서는 해당 메서드를 사용할 수 없다.
- 더불어, 메서드의 이름을 변경할 수 없고 Spring에서 명시한 메서드 이름을 그대로 사용해야 한다.
- 이처럼 두 인터페이스를 사용한 코드는 Spring Framework에 의존적인 코드가 된다.
- 이와 같은 이유로 현재는 사용되지 않는 방법이다.
4. 설정 파일을 이용한 방법
- 설정 파일에는 @Bean을 이용하여 Bean을 등록한다.
- 이때 @Bean의 옵션을 이용하여 초기화 및 소멸 메서드를 명시할 수 있다.
a) @Bean 옵션
- @Bean에는 initMethod와 destroyMethod라는 옵션이 존재한다.
- 다음 예시 코드를 참고하자.
@Bean(initMethod = "초기화 메서드 이름", destroyMethod = "소멸 메서드 이름")
- 이처럼 해당 Bean에서 사용할 초기화 메서드와 소멸 메서드를 등록할 수 있다.
- Spring은 해당 Bean의 초기화 및 소멸 시점에서 해당 메서드를 호출한다.
b) @Bean 옵션 사용의 장점
- 메서드의 이름을 자유롭게 명시할 수 있다.
- Spring Framework에 의존적이지 않다.
- 설정 정보를 기반으로 코드를 고칠 수 없는 외부 라이브러리에도 적용할 수 있다.
c) destroyMethod 옵션의 특별한 기능
- destroyMethod의 기본 값은 "(inferred)"로 되어 설정되어있다.
- 이는 문자열로, "추론"을 의미하는 값이다. 여기에 특별한 기능이 있다.
- 기본 값의 이름을 "추론"이라 명시한 이유는...
- 외부 라이브러리가 사용하는 소멸 메서드의 이름을 종료 시점에 알아서 호출하기 때문이다.
- 일반적으로 외부 라이브러리의 Bean 종료 메서드는 close, shutdown과 같은 이름으로 선언되어 있는데,
이를 알아서 호출해주는 것이다.
- 이와 같은 이유로 @Bean을 사용하는 경우, 종료 메서드를 따로 명시하지 않는 경우가 많다.
- 만약 추론기능을 사용하고 싶지 않다면, 다음과 같이 공백을 명시하면 된다.
@Bean(destroyMethod = "")
5. @PostContruct, @PreDestroy
- 어노테이션의 이름만 봐도 그 기능이 무엇인지 직관적으로 알 수 있지 않은가?
- @PostContruct는 초기화 메서드에, @PreDestroy 소멸 메서드에 부착하면 된다.
a) 장점
- 사용이 간단하다. 메서드에 해당 어노테이션을 부착하기만 하면 된다.
- Spring에서 공식적으로 권장하는 방법이다.
- 두 어노테이션은 Java에서 제공하는 기술이므로, Spring Framework에 의존적이지 않다. (javax.annotation)
b) 단점
- 외부 라이브러리에 적용할 수 없다.
- 그러므로 외부 라이브러리에 초기화 및 종료 메서드를 적용하고 싶다면 @Bean을 이용한 방식을 사용해야 한다.
6. 결론
- 지금까지 Bean 생명주기 callback을 사용하는 방법 세 가지를 알아보았다.
- 이 세 가지 방법을 어떻게 사용하는 것이 가장 효율적인 방법일까?
- Java 어노테이션(@PostContruct, @PreDestroy)을 메인으로 사용하자.
- 만약 외부 라이브러리에 의한 실행이 필요하다면, @Bean을 이용한 방법을 함께 운용하자.
'Back-end > Spring 개념' 카테고리의 다른 글
17. Spring 기본개념 총정리 (2) | 2022.02.18 |
---|---|
16. Bean Scope에 대하여 (0) | 2022.02.17 |
14. Annotation을 만드는 방법 (0) | 2022.02.15 |
13. @Autowired의 다양한 문제 해결방법 (0) | 2022.02.14 |
12. Dependency Injection 방법 (0) | 2022.02.11 |
댓글