- Spring Container의 역할
- bean 객체의 생성, 초기화, 소멸 등 life-cycle 관리
- 어떻게?
- 각 bean에 대해 life-cycle 관련 메소드를 호출해서 실행함으로써 관리하는거야
1) Bean class(우리가 만든 클래스)에서 life-cycle랑 관련된 인터페이스의 callback 메소드를 구현
---> 그러면 그걸 스프링 컨테이너가 알아서 적절한 시점에 호출해서 실행시킴
ex) BeanNameAware.setBeanName()
---> 구현은 개발자가
= 스프링이 제공하는 특정 인터페이스를 상속받아 빈을 구현한다.
2) org.springframework.beans.factory.config.BeanPostProcessor를 구현한 클래스의 객체를 bean으로 등록하면
---> 메소드가 실행되면서 관리
3) Bean에 정의된 custom init 메소드 / destroy 메소드 호출
---> 클래스 내에서 이 메소드를 정의해줌
---> 그리고 xml 설정파일에서 <bean> 에다가 init-method, destroy-method 속성 부여
= 스프링 설정에서 특정 메소드를 호출하라고 지정한다.
즉, 정의는 개발자(우리)가 하지만 호출이나 실행은 컨테이너가 알아서 적절한 시점에 하는 것임.
★ BeanFactory의 Life-Cycle
- 객체 생성 / 프로퍼티 설정 → 초기화 → 사용 → 소멸
1. Bean 객체가 생성되고 Bean 프로퍼티가 설정되면서 DI 까지 다 된다.
2. Bean 객체가 BeanNameAware 인터페이스를 구현하고 있을 경우 setBeanName() 을 호출한다.
3. BeanFactory.setBeanFactory() 를 호출한다.
4. BeanPostProcessor의 초기화 전 처리 (BeanPostProcessor.postProcessorBeforeInitialization())
5. @PostConstruct 어노테이션 처리... (자바 코드 시)
6. InitializingBean.afterPropertiesSet() 호출한다.
7. 커스텀 init 메소드를 호출한다.
8. BeanPostProcessor의 초기화 후 처리
9. Bean 사용
10. @PreDestroy 어노테이션 처리... (자바 코드 시)
11. DisposableBean.destroy() 호출한다.
12. 커스텀 destroy 메소드를 호출한다.
13. 종료
- @PostConstruct를 사용해서 초기화했다면 @Predestroy 사용해서 소멸
- init 메소드를 사용해서 초기화했다면 destroy 메소드를 사용해서 소멸
★ Life-Cycle 관련 인터페이스 & callback 메소드 & annotation
- org.springframework.beans.factory.BeanNameAware
- 초기화 과정에서 bean의 이름(id)을 전달 받는다.
- bean에 id 줬었잖아 그게 넘어오는거야
- callback 메소드 : void setBeanName(String beanName)
- ~.BeanFactoryAware
- 이 인터페이스랑 메소드 이용하면 메인이 아닌 다른 클래스에서도 getBean() 같은거 사용 가능해짐
- callback 메소드 : void setBeanFactory(BeanFactory factory)
: bean 객체에게 bean을 관리하는 BeanFactory (컨테이너 객체) 객체를 전달 받음
: 한마디로 컨테이너 호출
- ~.ApplicationContextAware
- 이 인터페이스랑 메소드 이용하면 메인이 아닌 다른 클래스에서도 getBean() 같은거 사용 가능해짐
- callback 메소드 : void setApplicationContext(ApplicationContext context)
: bean 객체에게 bean을 관리하는 ApplicationContext (컨테이너 객체) 객체를 전달 받음
: 한마디로 컨테이너 호출
- ~.InitializingBean
- bean 초기화 과정에서 실행될 메소드 정의 인터페이스
- callback 메소드 : void afterPropertiesSet()
: bean 객체 생성 및 프로퍼티 초기화 (DI) 이후에 호출
= DI 끝난 다음에 호출
: 주로 프로퍼티 값 설정 결과를 검증하기 위해 사용
: 제대로 주입 됐는지 알 수 있음
: bean의 커스텀 init-method로 대체 가능
- ~.DesposableBean
- bean 소멸 과정에서 실행될 메소드 정의 인터페이스
- callback 메소드 : void destroy()
: bean 객체를 제거하기 전에 호출
: bean이 사용하던 자원 반납 수행
: bean의 커스텀 destroy-method로 대체 가능
- Annotations
- @PostConstruct 를 붙인 메소드
: bean 생성 및 DI 수행 직후 호출됨
: init-method 역할이랑 같아
: xml 설정 대신 annotation 방식 쓸 때 사용하는거야
: JSR-250
: <context:annotation-config /> 태그 필요
- @PreDestroy 를 붙인 메소드
: bean이 삭제되기 직전에 호출됨
: destroy-method 역할이랑 같아
★ BeanNameAware / BeanFactoryAware 코드 어떻게?
- 일단 인터페이스 사용하려면
class Instrumentalist implements Performer, BeanNameAware, BeanFactoryAware {
}
이렇게 구현 인터페이스 추가
- beanName은 String 타입이므로
private String beanName;
private BeanFactory factory;
필드 추가
- 세터 메소드 정의
@Override
public void setBeanName(String beanName) {
this.beanName = beanName;
}
===> beanName 가져오기위해 세터 메소드 필요
@Override
public void setBeanFactory(BeanFactory factory) {
this.factory = factory;
}
===> 컨테이너 사용하기 위해 컨테이너 객체 가져오는 세터 메소드 필요
===> 이걸 해야 getBean 메소드 사용해서 객체를 가져올 수 있으니까
===> 사용할 때는 factory.getBean("객체이름");
★ InitializingBean / DisposableBean 코드 어떻게?
- 일단 인터페이스 사용하려면
class Instrumentalist implements Performer, InitializingBean, DisposableBean {
}
이렇게 구현 인터페이스 추가
- 메소드 추가
public void afterPropertiesSet() throws Exception {
...
instrument.tune();
}
public void destroy() throws Exception {
instrument.clean();
}
★ 커스텀 init-method, destroy-method 코드 어떻게?
- 인터페이스 아니니까 implements 필요 없고
- 이름은 맘대로인 메소드를 정의하자
- init 때 실행 될 메소드 정의하고 destroy 때 실행 될 메소드 정의하고
public void tuneInstrument() {
instrument.tune();
}
public void cleanInstrument() {
instrument.clean();
}
- 그러고나서 어떻게 하느냐? xml 설정 파일 가서 <bean> 태그에 속성으로 연결시켜줌
<bean id="kenny" class="~"
init-method="tuneInstrument"
destroy-method="cleanInstrument"
... />
init 시점엔 tuneInstrument 메소드를 호출해!
destroy 시점엔 cleanInstrument 메소드를 호출해!