빈 라이프사이클과 범위
빈 라이프사이클과 범위
컨테이너 초기화와 종료
스프링 컨테이너는 초기화와 종료라는 라이프사이클을 갖는다.
// 컨테이너 초기화
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppContext.class);
// 컨테이너에서 빈 객체를 구해서 사용
Greeter g = ctx.getBean("greeter", Greeter.clas);
String msg = g.greet("스프링");
System.out.println(msg);
// 컨테이너 종료
ctx.close();
위 코드를 보면 AnnotationConfigApplicationContext의 생성자를 이용해서 컨텍스트 객체를 생성하는데 이 시점에 스프링 컨테이너를 초기화한다. 스프링 컨테이너는 설정 클래스에서 정보를 읽어와 알맞은 빈 객체를 생성하고 각 빈을 연결하는 작업을 수행한다.
컨테이너 초기화가 완료되면 컨테이너를 사용할 수 있다. 사용한다는 것은 getBean 같은 메서드를 이용해서 빈 객체를 구한다는 것을 뜻한다.
컨테이너 사용이 끝나면 컨테이너를 종료한다. close() 메서드는 AbstractApplicationContext 클래스에 정의되어 있다. 스프링 컨테이너의 라이프사이클에 따라 빈 객체도 자연스럽게 생성과 소멸이라는 라이프사이클을 갖는다.
스프링 빈 객체의 라이프 사이클
스프링 컨테이너는 빈 객체의 라이프사이클을 관리한다.
객체 생성 - 의존 설정 - 초기화 - 소멸
스프링 컨테이너를 초기화할 때 스프링 컨테이너는 가장 먼저 빈 객체를 생성하고 의존을 설정한다. 의존 자동 주입을 통한 의존 설정이 이 시점에 수행된다. 모든 의존 설정이 완료되면 빈 객체의 초기화를 수행한다. 빈 객체를 초기화하기 위해 스프링은 빈 객체의 지정된 메서드를 호출한다. 스프링 컨테이너를 종료하면 스프링 컨테이너는 빈 객체의 소멸을 처리한다. 이때에도 지정한 메서드를 호출한다.
- Client.java
public class Client implements InitializingBean, DisposableBean {
private String host;
public void setHost(String host) {
this.host = host;
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("Client.afterPropertiesSet() 실행");
}
public void send() {
System.out.println("Client.send() to " + host);
}
@Override
public void destroy() throws Exception {
System.out.println("Client.destroy() 실행");
}
}
빈 객체가 InitializingBean 인터페이스를 구현하면 스프링 컨테이너는 초기화 과정에서 빈 객체의 afterPropertiesSet() 메서드를 실행한다.
빈 객체가 DisposableBean 인터페이스를 구현하면 스프링 컨테이너는 소멸 과정에서 빈 객체의 destroy() 메서드를 실행한다.
- AppCtx.java
@Configuration
public class AppCtx {
@Bean
public Client client() {
Client client = new Client();
client.setHost("host");
return client;
}
}
콘솔에 출력된 메세지의 순서를 보면 먼저 afterPropertiesSet() 메서드를 실행하낟. 즉 스프링 컨테이너는 빈 객체 생성을 마무리한 뒤에 초기화 메서드를 실행한다. 가장 마지막에 destroy() 메서드를 실행한다. 이 메서드는 스프링 컨테이너를 종료하면 호출된다는 것을 알 수 있다.
빈 객체의 초기화와 소멸 : 커스텀 메서드
직접 구현한 클래스가 아닌 외부에서 제공받은 클래스를 스프링 빈 객체로 설정하고 싶을 때도 있다. 이 경우 소스 코드를 받지 않았다면 두 인터페이스를 구현하도록 수정할 수 없다. 이렇게 InitializingBean, Disposable 인터페이스를 구현할 수 없거나, 이 두 인터페이스를 사용하고 싶지 않은 경우에 스프링 설정에서 직접 메서드를 지정할 수 있다.
방법은 @Bean 태그에서 initMethod 속성과 destroyMethod 속성을 사용해서 초기화 메서드와 소멸 메서드의 이름을 지정하면 된다.
- Client2.java
public class Client2 {
private String host;
public void setHost(String host) {
this.host = host;
}
public void connect() {
System.out.println("Client2.connect() 실행");
}
public void send() {
System.out.println("Client2.send() to " + host);
}
public void close() {
System.out.println("Client2.close() 실행");
}
}
Client2 클래스를 빈으로 사용하려면 초기화 과정에서 connect() 메서드를 실행하고 소멸 과정에서 close() 메서드를 실행해야 한다면 @Bean 애노테이션의 initMethod, destroyMethod 속성에 초기화와 소멸 과정에서 사용할 메서드 이름을 지정해주면 된다.
@Bean(initMethod = "connect", destroyMethod = "close")
public Client2 client2() {
Client2 client = new Client2();
client.setHost("host");
return client;
}
빈 객체의 생성과 관리 범위
스프링 컨테이너는 빈 객체를 한 개만 생성한다고 했따. 이렇게 한 식별자에 대해 한 개의 객체만 존재하는 빈은 싱글톤(singleton) 범위를 갖는다. 사용빈도가 낮긴 하지만 프로토타입 범위의 빈을 설정할 수도 있다.
빈의 범위를 프로토타입으로 지정하면 빈 객체를 구할 때마다 매번 새로운 객체를 생성한다.
특정 빈을 프로토타입 범위로 지정하려면 다음과 같이 값으로 "prototype"을 갖는 @Scope 애노테이션을 @Bean 애노테이션과 함께 사용하면 된다.
@Configuration
public class AppCtxWithPrototype {
@Bean
@Scope("prototype")
// @Scope("singleton") 가능
public Client client() {
Client client = new Client();
client.setHost("host");
return client;
}
}
프로토타입 범위를 갖는 빈은 완전한 라이프사이클을 따르지 않는다는 점에 주의해야 한다. 스프링 컨테이너는 프로토타입의 빈 객체를 생성하고 프로퍼티 설정, 초기화 작업까지는 수행하지만, 컨테이너 종료시에 생성한 프로토타입 빈 객체의 소멸 메서드를 실행하지는 않는다. 프로토타입 범위의 빈을 사용할 때에는 빈 객체의 소멸 처리를 직접 해야 한다.
Author And Source
이 문제에 관하여(빈 라이프사이클과 범위), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@shiningcastle/빈-라이프사이클과-범위저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)