스프링에서 프록시 활용하기

JooHeon·2021년 12월 17일
0

🖊 직접 빈(Bean) 등록으로 사용하는 방법

직접 @Configuration을 이용해서 수동으로 빈을 등록하는 방법이다.

@Bean
public OrderRepository orderRepository(LogTrace logTrace){
    OrderRepository orderRepository = new OrderRepository();
    ProxyFactory factory = new ProxyFactory(orderRepository);

    factory.addAdvisor(getAdvisor(logTrace));
    OrderRepository proxy = (OrderRepository) factory.getProxy();
    return proxy;
}

private Advisor getAdvisor(LogTrace logTrace) {
    //pointcut
    NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
    pointcut.setMappedNames("request*", "order*", "save*");

    LogTraceAdvice logTraceAdvice = new LogTraceAdvice(logTrace);
    return new DefaultPointcutAdvisor(pointcut, logTraceAdvice);
}

빈으로 직접 ProxyFactory를 실제 객체를 프록시 객체로 바꾸고 반환한다.
이 경우에는 실제 객체를 바로 주입하는 @ComponentScan을 실제 객체에 달 수 없다.
이를 포함하는 @Repository, @Service, @Controller도 당연히 불가능하다.
프록시 객체를 생성해주기 위해서 너무 많은 설정 작업이 필요해서 나온 방법이 빈 후처리기가 있다.

🖊 빈 후처리기(BeanPostProcessor)

스프링의 빈 등록 과정은
1. 스프링이 빈 대상이 되는 객체를 생성하고
2. 생성된 객체를 빈 저장소에 등록하기 직전에 빈 후처리기에 전달한다.
3. 빈 후처리기는 객체를 조작하거나 객체를 바꿔칠 수도 있다. 이후 객체를 반환한다.
4. 반환된 객체는 빈 저장소에 등록된다.

// BeanPostProcessor는 인터페이스로 PostConstructor 이후 혹은 이전에 조작할지 정할 수 있다.
// BeanPostProcessor를 상속받는 클래스를 Bean으로 등록만 해주면 된다.
    @Test
    public void beanPostConfig() throws Exception{
        // 스프링 컨테이너
        AnnotationConfigApplicationContext applicationContext = 
        new AnnotationConfigApplicationContext(BeanPostConfigProcessor.class);

        //B는 빈으로 등록된다.
        B b = applicationContext.getBean("beanA", B.class);
        b.helloB();

        //A는 빈으로 등록되지 않는다.
        Assertions.assertThrows(NoSuchBeanDefinitionException.class, 
        () -> applicationContext.getBean(A.class));
    }

    @Slf4j
    @Configuration
    static class BeanPostConfigProcessor {
        @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;
        }
    }

🖊 @PostConstructor

@PostConstructor는 스프링 빈 생성 이후에 빈을 초기화하는 역할을 한다.
메소드에 어노테이션만 붙여줘도 빈 생성 이후 한 번더 조작을 해주는데, 이 말은
스프링이 기본적으로 호출하는 빈 후처리기가 있다는 것이다.
스프링은 CommonAnootationBeanPostProccessor라는 빈 후처리기를 자동으로 등록하는데
여기서 @PostConstructor 어노테이션이 붙은 메소드를 자동으로 호출한다.

🖊 AutoProxyCreator

스프링 스타터 aop 라이브러리를 추가하면 AopAutoConfiguration에서 AOP와 관련된 클래스들을 bean으로 추가한다. 여기서 AnnotationAspectJAutoProxyCreator라는 빈 후처리기가 스프링 빈에 자동으로 등록되는데, 스프링 빈으로 등록된 Advisor를 찾아서 프록시가 필요한 곳에 자동으로 프록시를 적용해준다. 추가로 @AspectJ와 관련된 AOP 기능도 찾아서 처리해준다.

  • 작동 과정
  1. 빈 대상 객체 생성
  2. 빈 후처리기에 전달
  3. 모든 Advisor 빈 조회
  4. 프록시 적용 대상 체크
  5. 프록시 생성
  6. 빈 등록

0개의 댓글