스프링 빈의 생성 과정은 대략 다음과 같다.
- 객체 생성
- 의존성 주입
단, 생성자 주입 방식은 예외다. 객체 생성과 동시에 의존성 주입이 일어난다.
생성자의 호출 시점을 생각해보면 당연한 이야기다.
스프링 빈은 객체가 생성된 후, 필요한 의존성을 모두 주입받은 다음에 자신의 작업을 시작해야 한다.
의존성을 주입받기 전에 작업을 시작하면, 의도와 다르게 동작할 가능성이 높다.
다음 코드는 그 예시를 단적으로 보여준다.
NetworkClient 클래스는 setter를 통해 url을 주입받는다.
스프링 빈을 주입받지는 않고, String 타입 객체를 외부에서 주입받을 뿐이다.
생성자 호출 시점에서 url을 바탕으로 연결을 생성하고 데이터를 전송하는 초기 작업을 수행한다. (connect(), call())
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 call(String message) {
System.out.println("call(): " + url + ", message = " + message);
}
// 빈 생성 시 수행할 동작
public void connect() {
System.out.println("connect(): " + url);
}
// 빈 소멸 직전 수행할 동작
public void disconnet() {
System.out.println("disconnet(): " + url);
}
}
NetworkClient 클래스를 기반으로 동작하는 아래 테스트 코드는 의도대로 동작하지 않는다.
public class BeanLifeCycleTest {
@Test
public void lifeCycleTest() {
ConfigurableApplicationContext ac = new AnnotationConfigApplicationContext(LifeCycleConfig.class);
NetworkClient bean = ac.getBean(NetworkClient.class);
// close(): 스프링 컨테이너 내리는 메서드
// close() 메서드는 ApplicationContext 타입에는 정의 안돼있음. 하위 인터페이스나 클래스 타입 참조변수로 접근해야함.
ac.close();
}
@Configuration
static class LifeCycleConfig {
@Bean
public NetworkClient networkClient() {
NetworkClient networkClient = new NetworkClient();
networkClient.setUrl("https://testUrl.url");
return networkClient;
}
}
}
연결 생성 및 데이터 전송 (connect(), call()) 작업이 setUrl() 호출 이전,
즉 생성자 호출 시점에 이루어지기 때문에 url이 null인 상태로 작업이 수행된다.
이렇게 connect()와 같은 메서드들은 의존성 주입이 끝난 다음에 호출되어야 한다.
스프링 빈의 이벤트 라이프사이클
스프링 빈의 생성부터 소멸까지의 라이프사이클은 다음과 같다.
- 스프링 컨테이너 생성
- 스프링 빈 생성
- 의존관계 주입
- 초기화 콜백
- 빈이 생성되고, 의존성 주입이 완료된 직후 호출
- 사용
- 소멸 전 콜백
- 빈이 소멸되기 직전에 호출
- 스프링 컨테이너 종료
스프링은 콜백 메서드를 통해 빈의 의존성 주입 완료 및 소멸 시점을 알려주는 기능을 제공한다.
+) 객체 생성과 초기화를 분리하는 이유 (단일 책임 원칙)
객체 생성은 파라미터를 통해 필요한 값들을 설정하고 메모리를 할당하는 등 객체를 생성하는 일에 집중해야 한다.
반면 초기화는 객체 생성 후 DB 커넥션 등 무거운 초기 작업을 수행하는데 집중해야 한다.
이러한 작업들은 서로 분리하는 것이 유지보수 측면에서 유리하며, 객체 지향의 단일 책임 원칙(SRP)을 잘 보여주는 사례이기도 하다.
+) 빈의 생명주기
싱글톤 빈은 스프링 컨테이너와 생명주기를 같이 하지만, 생명주기가 더 짧은 빈들도 있다.
소멸 콜백 메서드는 스프링 빈에 따라서 컨테이너가 종료 전에도 호출될 수 있다.
즉 콜백 메서드는 컨테이너보다는 스프링 빈의 생명주기에 초점을 두어야 한다.
'[inflearn] 스프링 핵심 원리 - 기본편 > 섹션 8 - 빈 생명주기 콜백' 카테고리의 다른 글
8-2. 빈 생명주기 콜백 사용법 (0) | 2024.05.27 |
---|