빈 후처리기는 스프링이 빈을 초기화하는 과정 중에서 데이터를 가로채서 조작하거나 변경하는 기능을 가진다.
public class BasicTest {
@Test
void basicConfig() {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(BasicConfig.class);
//A는 빈으로 등록된다
A a = applicationContext.getBean("beanA", A.class);
a.helloA();
//B는 빈으로 등록되지 않는다.
Assertions.assertThrows(NoSuchBeanDefinitionException.class,()-> applicationContext.getBean(B.class));
}
static class BasicConfig{
@Bean(name= "beanA")
public A a(){
return new A();
}
}
@Slf4j
static class A{
public void helloA(){
log.info("hello A");
}
}
@Slf4j
static class B{
public void helloB(){
log.info("hello B");
}
}
}
@Bean을 이용해 A클래스의 객체를 생성하고 빈으로 등록한다. 그리고 이를 구현한 클래스를
AnnotationConfigApplicationContext 에 등록하면 beanA가 스프링 컨테이너에 저장된다.빈 후처리기는 스프링이 빈을 초기화하는 과정 중에서 데이터를 가로채서 조작하거나 변경하는 기능을 가진다.
package hello.proxy.postprocessor;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
public class BeanPostProcessorTest {
@Test
void basicConfig() {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanPostProcessorConfig.class);
//beanA 이름으로 B 객체가 빈으로 등록된다
B b = applicationContext.getBean("beanA", B.class);
b.helloB();
//A는 빈으로 등록되지 않는다.
Assertions.assertThrows(NoSuchBeanDefinitionException.class,()-> applicationContext.getBean(A.class));
}
static class BeanPostProcessorConfig{
@Bean(name= "beanA")
public A a(){
return new A();
}
@Bean
public AtoBPostProcessor helloPostProcessor(){
return new AtoBPostProcessor();
}
}
@Slf4j
static class A{
public void helloA(){
log.info("hello A");
}
}
@Slf4j
static class B{
public void helloB(){
log.info("hello B");
}
}
@Slf4j
static class AtoBPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
log.info("beanName={} bean={}",beanName,bean);
if (bean instanceof A){
return new B();
}
return bean;
}
}
}
같은 방식으로 A, B 클래스를 만들고 A를 bean에 등록했지만, 이번에는 BeanPostProcessor를 상속받은 클래스의
postProcessAfterInitialization 메서드를 상속하여 bean을 조작하여 A클래스가 빈에 등록되기 전에 B 클래스로 바꿔치기하여 스프링 컨테이너에 저장했다.
BeanPostProcessor 인터페이스는
postProcessAfterInitialization(빈이 초기화 된 후에 조작) 메서드와
postProcessBeforeInitialization (빈이 초기화 되기 전에 조작)메서드가 존재한다.
빈의 생명주기는
생성 -> 의존성주입 -> 초기화 -> 사용 -> 소멸인데
BeanPostProcessor는 빈의 생성주기 중 초기화에 관여하는 것이다.
postProcessBeforeInitialization
이 시점에서 빈의 상태를 조작하면 초기화 콜백에서 이 조작된 상태를 기반으로 추가적인 초기화 작업을 수행할 수 있다.
예를 들어, 특정 필드를 검증하거나 기본값을 설정하는 등의 작업이 이 시점에서 유용할 수 있다.
postProcessAfterInitialization
이 시점에서는 빈이 완전히 초기화된 상태이다.
따라서 빈의 상태를 변경하거나 프록시를 만들어서 원래의 빈을 감싸는 등의 작업을 수행한다.
'Java > 스프링 AOP' 카테고리의 다른 글
실시간 하이픈 붙이기 (0) | 2023.08.30 |
---|---|
빈 후처리기 (2) 스프링 AOP (0) | 2023.08.24 |
ProxyFactory(2) 포인트컷, 어드바이스, 어드바이저 (0) | 2023.08.21 |
ProxyFactory (1) CGLIB, JDK 동적 프록시 (0) | 2023.08.20 |
CGLIB (0) | 2023.08.19 |