이번 글에서는 빈 후처리기를 크게 3가지로 알아보려고 합니다.
- 빈 후처리기
- 빈 후처리기 - 예제코드
- 스프링이 제공하는 빈 후처리기
빈 후처리기란?
빈 후처리기는 스프링이 @Bean 혹은 컴포넌트 스캔으로 생성한 객체를 스프링 컨테이너에 등록하기 전에 조작하는 기술입니다. 빈 후처리기를 사용하기 위해서는 BeanPostProcessor라는 인터페이스를 구현해야하는데, BeanPostProcessor인터페이스의 Default메서드인 postProcessAfterInitialization를 Override하여 구현하면 됩니다.
일반적인 빈 후처리기의 과정을 보도록 하겠습니다.
- 스프링은 @Bean 혹은 컴포넌트 스캔 대상이되는 빈객체를 생성합니다(ex : A객체)
- 스프링 컨테이너(빈 저장소)에 등록하기 전에 빈 후 처리기에 A객체를 전달합니다.
- 빈 후처리기는 전달받은 A객체를 조작하거나 객체를 변경할 수 있습니다.
- 최종적으로 스프링 컨테이너(빈 저장소)에 A객체를 등록합니다.
빈 후처리기를 통해 객체가 변경되는 과정을 보도록 하겠습니다.
- 스프링은 @Bean 혹은 컴포넌트 스캔 대상이되는 빈객체를 생성합니다(ex : A객체)
- 스프링 컨테이너(빈 저장소)에 등록하기 전에 빈 후 처리기에 A객체를 전달합니다.
- 빈 후처리기는 A객체를 B객체로 변경합니다.
- 최종적으로 스프링 컨테이너(빈 저장소에)에 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);
}
테스트 코드를 간단히 보면
- 테스트 코드의 new AnnotationConfigApplicationContext(BeanPostProcessorConfig.class)는 스프링 컨테이너를 만들고 BeanPostProcessorConfig안에 선언된 Bean객체를 생성합니다.
- BeanPostProcessorconfig에는 2개의 @Bean이 붙어있는데, 하나는 A객체 다른 하나는 BeanPostProcessor을 구현한 빈 후처리기입니다.
- 빈 후처리기를 빈으로 등록하게 되면, 스프링은 빈객체를 등록하기전에 빈 후처리기에 등록할 빈객체를 전달하고 빈 후처리기는 전달받은 객체를 조작하게 됩니다.
- 결과적으로 BeanPostProcessorConfig파일에는 A객체를 빈으로 등록하려고 설정하였지만, 스프링컨테이너에 등록된 객체는 B객체라는 것을 알 수 있습니다.
이렇게 빈 후처리기를 이용하면 개발자가 등록하는 모든 빈을 중간에 조작할 수 있다는 의미가 됩니다.
즉, 필요에따라서는 빈 객체를 프록시 객체로 변경할 수 있다는 의미입니다.
스프링이 제공하는 빈 후처리기
위 글에서는 빈 후처리기를 사용하여 스프링 컨테이너에 등록되기 전에 객체를 조작하는 방법을 알아보았습니다.
하지만, 빈 후처리기를 사용하기 위해서 개발자가 매번 저렇게 코드를 작성하는 것은 비효율적이기때문에 스프링에서는 빈 후처리기를 제공하고 있습니다.
스프링에서 제공하는 빈 후처리기를 사용하기 위해서는 라이브러리를 추가해줘야합니다.
implementation 'org.springframework.boot:spring-boot-starter-aop'
이 라이브러리를 추가해주면 스프링은 AnnotationAwareAspectJAutoProxyCreator라는 자동으로 프록시를 생성해주는 빈 후처리기를 만들어주는데, AnnotationAwareAspectJAutoProxyCreator는 앞에서 공부한 BeanPostProcessor와 비슷한 역할을 합니다.
아래 이미지는 자동 프록시 생성기의 동작과정입니다.
- 스프링은 @Bean 혹은 컴포넌트 스캔 대상이되는 빈객체를 생성합니다.(ex : A객체)
- 스프링 컨테이너(빈 저장소)에 등록하기 전에 자동 프록시 생성기(빈 후처리기)에 A객체를 전달합니다.
- 스프링 컨테이너에 있는 모든 Advisor을 조회합니다.
- Advisor는 PointCut과 Advice로 구성되어있는데 PointCut을 통해 프록시 적용 대상여부를 체크합니다.
- 프록시 적용 대상이면 프록시 객체를 생성하고, 적용 대상이 아니면 원본객체를 생성합니다.
- 스프링 컨테이너(빈 저장소)에 생성된 객체를 등록합니다.
스프링에서 제공하는 자동 프록시 생성기를 사용하게 되면서 개발자는 더 이상 빈 후처리기에 신경을 쓰지 않고, 스프링빈에 등록하게 될 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 |