본문 바로가기

Java and Spring

[Spring] 빈 후처리기

이번 글에서는 빈 후처리기를 크게 3가지로 알아보려고 합니다.

 

  • 빈 후처리기
  • 빈 후처리기 - 예제코드
  • 스프링이 제공하는 빈 후처리기
빈 후처리기란?

빈 후처리기는 스프링이 @Bean 혹은 컴포넌트 스캔으로 생성한 객체를 스프링 컨테이너에 등록하기 전에 조작하는 기술입니다. 빈 후처리기를 사용하기 위해서는 BeanPostProcessor라는 인터페이스를 구현해야하는데, BeanPostProcessor인터페이스의 Default메서드인 postProcessAfterInitialization를 Override하여 구현하면 됩니다.

 

일반적인 빈 후처리기의 과정을 보도록 하겠습니다.

  1. 스프링은 @Bean 혹은 컴포넌트 스캔 대상이되는 빈객체를 생성합니다(ex : A객체)
  2. 스프링 컨테이너(빈 저장소)에 등록하기 전에 빈 후 처리기에 A객체를 전달합니다.
  3. 빈 후처리기는 전달받은 A객체를 조작하거나 객체를 변경할 수 있습니다.
  4. 최종적으로 스프링 컨테이너(빈 저장소)에 A객체를 등록합니다.

빈 후처리기를 통해 객체가 변경되는 과정을 보도록 하겠습니다.

  1. 스프링은 @Bean 혹은 컴포넌트 스캔 대상이되는 빈객체를 생성합니다(ex : A객체)
  2. 스프링 컨테이너(빈 저장소)에 등록하기 전에 빈 후 처리기에 A객체를 전달합니다.
  3. 빈 후처리기는 A객체를 B객체로 변경합니다.
  4. 최종적으로 스프링 컨테이너(빈 저장소에)에 A객체가 아닌 B객체를 등록합니다.

 

빈 후처리기 - 예제코드

[A객체와 AToBPostProcessor객체를 스프링빈으로 등록]

@Slf4j
@Configuration
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;
    }
}

 

[테스트 코드]

@Test
void basicConfig() {
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(BeanPostProcessorConfig.class);

    //beanA 이름으로 B 객체가 빈으로 등록된다.
    B b = applicationContext.getBean("beanA", B.class);
    b.helloB();

    //A는 빈으로 등록되지 않는다.
    B bean = applicationContext.getBean(B.class);
}

테스트 코드를 간단히 보면

  1. 테스트 코드의 new AnnotationConfigApplicationContext(BeanPostProcessorConfig.class)는 스프링 컨테이너를 만들고 BeanPostProcessorConfig안에 선언된 Bean객체를 생성합니다.
  2. BeanPostProcessorconfig에는 2개의 @Bean이 붙어있는데, 하나는 A객체 다른 하나는 BeanPostProcessor을 구현한 빈 후처리기입니다.
  3. 빈 후처리기를 빈으로 등록하게 되면, 스프링은 빈객체를 등록하기전에 빈 후처리기에 등록할 빈객체를 전달하고 빈 후처리기는 전달받은 객체를 조작하게 됩니다.
  4. 결과적으로 BeanPostProcessorConfig파일에는 A객체를 빈으로 등록하려고 설정하였지만, 스프링컨테이너에 등록된 객체는 B객체라는 것을 알 수 있습니다.

이렇게 빈 후처리기를 이용하면 개발자가 등록하는 모든 빈을 중간에 조작할 수 있다는 의미가 됩니다.

즉, 필요에따라서는 빈 객체를 프록시 객체로 변경할 수 있다는 의미입니다.

 

스프링이 제공하는 빈 후처리기

위 글에서는 빈 후처리기를 사용하여 스프링 컨테이너에 등록되기 전에 객체를 조작하는 방법을 알아보았습니다.

하지만, 빈 후처리기를 사용하기 위해서 개발자가 매번 저렇게 코드를 작성하는 것은 비효율적이기때문에 스프링에서는 빈 후처리기를 제공하고 있습니다.

 

스프링에서 제공하는 빈 후처리기를 사용하기 위해서는 라이브러리를 추가해줘야합니다.

implementation 'org.springframework.boot:spring-boot-starter-aop'

이 라이브러리를 추가해주면 스프링은 AnnotationAwareAspectJAutoProxyCreator라는 자동으로 프록시를 생성해주는 빈 후처리기를 만들어주는데, AnnotationAwareAspectJAutoProxyCreator는 앞에서 공부한 BeanPostProcessor와 비슷한 역할을 합니다.

 

아래 이미지는 자동 프록시 생성기의 동작과정입니다.

  1. 스프링은 @Bean 혹은 컴포넌트 스캔 대상이되는 빈객체를 생성합니다.(ex : A객체)
  2. 스프링 컨테이너(빈 저장소)에 등록하기 전에 자동 프록시 생성기(빈 후처리기)에 A객체를 전달합니다.
  3. 스프링 컨테이너에 있는 모든 Advisor을 조회합니다.
  4. Advisor는 PointCut과 Advice로 구성되어있는데 PointCut을 통해 프록시 적용 대상여부를 체크합니다.
  5. 프록시 적용 대상이면 프록시 객체를 생성하고, 적용 대상이 아니면 원본객체를 생성합니다.
  6. 스프링 컨테이너(빈 저장소)에 생성된 객체를 등록합니다.

스프링에서 제공하는 자동 프록시 생성기를 사용하게 되면서 개발자는 더 이상 빈 후처리기에 신경을 쓰지 않고, 스프링빈에 등록하게 될 Advisor만 선언함으로써 편리하게 사용할 수 있게 되었습니다.

'Java and Spring' 카테고리의 다른 글

[Java] Message Digest 암호화 방식  (0) 2021.12.22
[Spring] 스프링 AOP  (0) 2021.12.15
[Spring] 프록시 팩토리  (0) 2021.12.08
[Java] CGLIB(Code Generator Library)  (0) 2021.12.04
[Java] 동적 프록시(Dynamic Proxy)  (0) 2021.12.01