일반적인 싱글톤 타입의 스프링 빈의 생명주기는 다음과 같다
스프링 컨테이너 생성 → 스프링 빈 생성 → 의존관계 주입 → 초기화 콜백 → 사용 → 소멸 전 콜백 → 스프링 종료
Spring은 기본적으로 객체로 만들 빈 설정정보(BeanDefinition)를 만들어둔 다음에 이를 바탕으로 객체를 생성한다. 이때 빈 설정정보(BeanDefinition)를 불러오고 조작하는 것이 빈팩토리 후처리기(BeanFactoryPostProcessor
)이며, 모든 빈들이 만들어진 직후에 객체의 내용이나 객체 자체를 변경하기 위한 것이 빈 후처리기(BeanPostProcessor
) 이다.
BeanFactoryPostProcessor
구현체를 빈으로 등록해 주어야 하는 경우는 대표적으로@Value
를 이용하는 경우가 있다
static
을 붙혀 컨테이너의 라이프사이클 초기에 다른 빈들보다 먼저 등록되도록 한다.postProcessBeanFactoy(ConfigurableListableBeanFactory beanFactory)
메서드를 구현해서 사용한다
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
stream(beanFactory.getBeanDefinitionNames())
.map(beanFactory::getBeanDefinition)
.filter(beanDefinition -> beanClassNameContains(beanDefinition, "module01.question13.beans"))
.map(BeanDefinition::getBeanClassName)
.forEach(System.out::println);
}
private boolean beanClassNameContains(BeanDefinition beanDefinition, String subString) {
return beanDefinition.getBeanClassName() != null && beanDefinition.getBeanClassName().contains(subString);
}
}
빈팩토리 후처리기 예시 ⇒ 특정 이름의 빈을 필터링 하는 후처리기postProcessBeforeInitialization()
, postProcessAfterInitialization()
두가지를 제공한다postProcessBeforeInitialization()
: 초기화 이전 전처리postProcessAfterInitialization()
: 초기화 이후 전처리static
을 붙혀 컨테이너의 라이프사이클 초기에 다른 빈들보다 먼저 등록되도록 한다.Initialization Method : 빈 초기화 시점에 프로퍼티 및 의존성 주입에 대한 조작을 위한 메서드
Destory Method : 애플리케이션이 종료되고 빈이 소멸되기 전에 실행되는 메서드
Initialization Method 생성방법
@PostConstruct
어노테이션을 붙혀준다InitializingBean
인터페이스 구현 (InitializingBean::afterPropertiesSet
)@Bean(initMethod=””)
Destroy Method 생성방법
@PreDestroy
어노테이션을 붙혀준다DisposableBean
인터페이스 구현 (Disposable::destroy
)@Bean(destroyMethod=””)
public class Runner {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfiguration.class);
context.registerShutdownHook();
}
}
public class CustomBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization on " + bean.getClass().getSimpleName());
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization on " + bean.getClass().getSimpleName());
return bean;
}
}
@ComponentScan
public class ApplicationConfiguration {
@Bean
public static CustomBeanPostProcessor customBeanPostProcessor() {
return new CustomBeanPostProcessor();
}
@Bean(initMethod = "initMethod", destroyMethod = "destroyMethod")
public SpringBean1 springBean1() {
return new SpringBean1();
}
}
public class SpringBean1 implements InitializingBean, DisposableBean {
@PostConstruct
public void postConstruct() {
System.out.println(getClass().getSimpleName() + "::postConstruct");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println(getClass().getSimpleName() + "::afterPropertiesSet");
}
public void initMethod() {
System.out.println(getClass().getSimpleName() + "::initMethod");
}
@PreDestroy
public void preDestroy() {
System.out.println(getClass().getSimpleName() + "::preDestroy");
}
@Override
public void destroy() throws Exception {
System.out.println(getClass().getSimpleName() + "::destroy");
}
public void destroyMethod() {
System.out.println(getClass().getSimpleName() + "::destroyMethod");
}
}
Runner 실행결과
...
postProcessBeforeInitialization on SpringBean1
SpringBean1::postConstruct
SpringBean1::afterPropertiesSet
SpringBean1::initMethod
postProcessAfterInitialization on SpringBean1
SpringBean1::preDestroy
SpringBean1::destroy
SpringBean1::destroyMethod
스프링 빈은 기본적으로 스프링 컨테이너가 생성될때 같이 생성되면서 컨테이너가 종료될때까지 유지되는 구조이다. 하지만 이는 스프링 빈의 기본이 싱글톤(Singleton)스코프로 생성되기 때문이다. 이때 스코프란 말 그대로 빈이 존재할 수 있는 범위 를 뜻한다.
@Component
, @Bean
어노테이션과 함께 사용
Scope | Description | |
---|---|---|
Singleton(Default) | 컨테이너 내 단 하나의 인스턴스만 존재, 컨테이너 종료시 소멸 | Eager Loading Default |
Prototype | 호출이 있을때 마다 생성되고 호출이 종료되면 소멸 | Lazy Loading Dafault |
Request | Http 호출이 있을때 마다 인스턴스가 생성되고 response 이후 소멸 | Lazy Loading Dafault |
Session | HTTP 세션마다 하나의 빈을 생성 세션 종료시 소멸 | |
Application | ServeltContext라이프사이클 동안 한개의 빈만 사용 | |
Websocket | websocket 라이프사이클 안에서 한개의 빈만 사용 |
어떤 이유로 특정 bean 은 늦게 초기화되기를 원한다면 다음 방법으로 빈의 로딩시점을 조정할 수 있다.
@ComponentScan
의 attribute 중 lazyInit 값을 true로 수정(default ⇒ false)@ComponentScan(lazyInit = true)
public class ApplicationConfiguration {
@Bean
...
}
@Component
, @Bean
선언과 함께 @Lazy
를 붙혀 지연로딩으로 설정@Component
@Lazy
public class SpringBean {...}
@ComponentScan
public class ApplicationConfiguration {
@Bean
@Lazy
...
}