빈 후처리기는 스프링이 빈을 초기화하는 과정 중에서 데이터를 가로채서 조작하거나 변경하는 기능을 가진다.

 

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

+ Recent posts