현재 포스팅은 영한님의 스프링의 핵심원리 - 기본편을 바탕으로 작성한 포스팅입니다 :)
스프링 빈 라이프 사이클
스프링에서 빈의 라이프 사이클은 다음과 같습니다
스프링 IOC 컨테이너 생성 -> 스프링 빈 생성 -> 의존관계 주입 -> 초기화 콜백 메서드 호출 -> 사용 -> 소멸전 콜백 메서드 호출 -> 스프링 종료
이때 만약 생성자 주입 방식을 경우엔 스프링 빈 생성과 함께 의존관계가 주입이 되겠죠??
우선 스프링 애플리케이션 실행 시 스프링 컨테이너가 생성되고, 컨테이너는 Bean Definition에 따라 각 Bean 객체를 인스턴스화합니다. Bean이 생성된 후, 컨테이너는 설정에 따라 각 Bean 간의 의존관계를 주입합니다. (Setter or 필드 주입, 생성자 주입의 경우 생성시 바로 의존관계 주입)
모든 의존성이 주입된 후, Bean이 InitializingBean 인터페이스를 구현하고 있다면 afterPropertiesSet() 메서드가 호출되거나, @PostConstruct 어노테이션이 붙은 메서드가 호출됩니다. 이렇게 모든 준비가 끝나면, 애플리케이션은 필요에 따라 컨테이너로 부터 Bean을 얻어와 사용하게 됩니다.
이후 애플리케이션이 종료되거나, 빈이 소멸되는 시점에 컨테이너는 Bean의 생명주기를 관리하는 일환으로 소멸전 콜백 메서드를 호출합니다. 이는 Disposable Bean 인터페이스의 destroy() 메서드 또는 @PreDestroy 어노테이션이 붙은 메서드, 또는 Bean 정의에서 지정한 사용자 소멸 메서드가 될 수 있습니다.
마지막으로 스프링 컨테이너 자체가 종료되며, 이 과정에서 모든 Singleton 스코프의 Bean들이 소멸됩니다.
콜백 메서드에 대해 간단히 다시 짚고 가자면, 스프링 프레임워크는 빈의 의존성 주입이 완료된 이후에 초기화 콜백 메서드를 호출함으로써 빈이 자신의 초기화 작업을 수행할 수 있는 시점임을 알려줍니다. 그리고 스프링 컨테이너가 종료될때, 소멸 콜백 메서드를 호출하여 빈이 필요한 정리 작업을 수행할 수 있는 시점임을 알려줍니다.이를 통해 빈은 자원을 해제하거나, 네트워크 연결을 종료 하는 등 소멸 과정에서 필요한 동작을 수행할 수 있습니다.
위 과정을 보시면서, 혹시 스프링 빈 라이프 사이클을 압축하기 위해 생성자 주입을 통해 빈 생성과 초기화를 동시에 진행하면 되지 않을까?? 라는 의문점이 드실 수 있습니다
결론적으로 우선 먼저 말씀드리면, 객체의 생성과 초기화를 분리하는 것이 좋습니다
생성자는 파라미터(필수 정보)를 받고, 메모리를 할당해서 객체를 생성하는 책임을 가집니다. 반면 초기화는 이렇게 생성된 값을 활용해서 외부 커넥션을 연결하는 등 무거운 동작을 수행합니다.
따라서 생성자 안에서 무거운 초기화 작업을 함께 하는 것 보다는 객체 생성하는 부분과 초기화 하는 부분을 명확히 나누는것이 유지보수 관점에서 더 좋습니다. 물론 초기화 작업이 내부 값들만 약간 변경하는 정도라면 생성자에서 한번에 처리하는것이 더 나을 수도 있습니다 :)
스프링은 크게 3가지 방법으로 빈 생명주기 콜백을 지원합니다.
- 인터페이스(InitializingBean, DisposableBean)
- 설정 정보에 초기화 메서드, 종료 메서드 지정
- @PostConstruct, @PreDestroy 애노테이션 지정
이 3가지 방법들에 대해 차근차근 알아보겠습니다!
1. 인터페이스 (InitializingBean, DisposableBean)
public class NetworkClient implements InitializingBean, DisposableBean {
private String url;
public NetworkClient() {
System.out.println("생성자를 호출, 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);
}
@Override
public void afterPropertiesSet() throws Exception {
// 이것이 의존 관계 주입이 끝난 뒤 호출해 주겠다라는 의미
connect();
call("초기화 연결 메세지");
}
@Override
public void destroy() throws Exception {
// 컨테이너가 내려가기 전에
disconnect();
}
}
위 코드는 인터페이스를 통해 생명주기 콜백을 적용하고 있습니다.
여기서 afterPropertiesSet() 안의 코드들이 의존 관계 주입이 끝난 뒤 호출되고, destroy() 안의 코드들이 컨테이너가 내려가지 전에 호출됩니다.
이러한 방식엔 여러 단점이 있습니다.
우선 인터페이스들이 스프링 전용 인터페이스여서, 코드가 스프링 전용 인터페이스에 의존하게 됩니다.
그리고 초기화, 소멸 메서드의 이름을 변경할 수 없고, 개발자가 코드를 고칠 수 없는 외부 라이브러리에 적용할 수 없습니다. 따라서 이 방법은 잘 사용하지 않습니다(초창기때 방법)
2. 빈 설정 정보에서 초기화 메서드, 종료 메서드 지정
public class ExampleBean {
public void initialize() throws Exception {
// 초기화 콜백 (의존관계 주입이 끝나면 호출)
}
public void close() throws Exception {
// 소멸 전 콜백 (메모리 반납, 연결 종료와 같은 과정)
}
}
@Configuration
class LifeCycleConfig {
@Bean(initMethod = "initialize", destroyMethod = "close")
public ExampleBean exampleBean() {
// 생략
}
}
위와 같이 빈 설정 정보를 통해 콜백 메서드를 적용하면 메서드 명을 자유롭게 부여할 수 있고, 스프링 코드에 의존하지 않는다는 장점을 가집니다. 또한 설정 정보를 사용하기 때문에 코드를 커스터마이징 할 수 없는 외부라이브러리에서도 적용이 가능합니다.
이때 @Bean의 destroyMethod에는 특별한 기능이 있습니다. @Bean의 destroyMethod는 기본 값이 (inferred) 즉, 추론으로 등록되어있습니다.따라서 close,shutdown등의 이름을 가진 메서드를 자동으로 호출해줍니다.
3. @PostConstruct, @PreDestroy 어노테이션
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class ExampleBean {
@PostConstruct
public void initialize() throws Exception {
// 초기화 콜백 (의존관계 주입이 끝나면 호출)
}
@PreDestroy
public void close() throws Exception {
// 소멸 전 콜백 (메모리 반납, 연결 종료와 같은 과정)
}
}
이 방법은 최신 스프링에서 가장 권장하는 방식으로 어노테이션 하나만 붙이면 되므로 매우 편리합니다.
이러한 어노테이션은 javax.annotion 패키지에 속해있습니다. 즉 스프링에 종속적인 기술이 아니라 JSR-250이라는 자바 표준을 준수한 것으로 스프링이 아닌 다른 컨테이너에서도 동작한다는 장점을 가집니다.
이러한 방법의 유일한 단점은 외부 라이브러리에 적용하지 못한다는 것인데, 해당 작업이 필요하다면 @Bean의 기능을 사용하는 것이 좋습니다.
'SPRING > 영한님 강의 - 스프링 핵심원리 기본편' 카테고리의 다른 글
빈 스코프(Singleton, Prototype, 웹 관련), 빈 스코프 활용하여 로그 (0) | 2023.07.11 |
---|---|
Spring Container, IOC, DI 완전 정복하기! (0) | 2023.07.09 |
좋은 객체 지향 프로그래밍이란 무엇일까(다형성, SOLID) (0) | 2023.07.08 |