BeanPostProcessor - AutoProxyCreator

목차

참고

본 포스트는 김영한의 스프링 핵심 원리 - 고급편 내용을 참고해 만들었습니다.

라이브러리 추가

implementation 'org.springframework.boot:spring-boot-starter-aop' //추가

자동 프록시 생성기 - AutoProxyCreator

스프링에서 AnnotationAwareAspectJAutoProxyCreator 라는 빈 후처리기가 등록됩니다.

AnnotationAwareAspectJAutoProxyCreator 는 스프링 빈으로 등록된 Advisor 를 자동으로 찾아 프록시 객체를 생성해줍니다. 또한, @AspectJ 와 관련된 AOP 기능도 자동으로 찾아서 처리해줍니다.

Bean 으로 등록하기 위한 객체를 생성 후 빈 후처리기에 전달합니다. 빈 후처리기 중 자동 프록시 생성 빈 후처리기에서 모든 Advisor 를 조회합니다. Advisor 에 포함된 Pointcut 을 사용해 프록시를 적용할 대상인지 확인합니다. 이때 객체의 패키지정보, 클래스 정보 와 해당 객체내 모든 메소드를 하나하나씩 매칭합니다.

Pointcut 조건이 하나라도 만족하면 해당 객체는 프록시 객체가 됩니다. AutoProxyCreator 에서 반환된 프록시 객체는 스프링 Bean 저장소에 Bean 으로 저장됩니다.

@Configuration
@Import({AppV1Config.class, AppV2Config.class})
public class AutoProxyConfig {

@Bean
public Advisor advisor1(LogTrace logTrace) {
// 이름 기반으로 한 NameMatchMethodPointcut
NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
pointcut.setMappedNames("request*", "order*", "save*");

// advice
LogTraceAdvice advice = new LogTraceAdvice(logTrace);

return new DefaultPointcutAdvisor(pointcut, advice);
}
}

포인트 컷의 사용

  1. 프록시 객체 생성 여부 판단 - 생성 단계
    • 프록시 생성단계에서 해당 빈이 프록시를 생성할 필요가 있는지 없는지 여부 판단하는데 사용합니다.
    • 클래스, 메소드 조건 모두 비교, 이때 모든 메소드를 확인합니다. 조건에 맞는 메서드가 하나라도 있으면 프록시 객체로 생성합니다.
  2. 어드바이스 적용 여부 판단 - 사용 단계
    • 프록시가 호출 됐을 때 어드바이스를 적용할지 여부를 포인트 컷을 이용해 확인한다.
    • orderControllerV1 의 request 메서드는 포인트 컷 조건에 만족하므로 Advice 를 먼저 호출한다.
    • orderControllerV1 의 nolog 메서드는 포인트 컷 조건을 만족하지 않으므로 Advice 를 호출하지 않는다.

AspectJExpressionPointcut

AspectJ 표현식을 사용해 프록시 객체를 생성할 수 있습니다.

AspectJExpressionPointcut 는 AsepctJ 표현식을 사용해 프록시 객체를 생성할 수 있습니다.

  • AspectJExpressionPointcut: AspectJ 표현식을 사용한 Advisor 생성
  • execution(* hello.proxy.app..*(..)): AspectJ 에서 제공하는 포인트컷 표현식
    • *: 모든 반환 타입
    • hello.proxy.app..
      • 해당 패키지와 그 하위 패키지
    • *(..)
      • * : 모든 메서드 이름
    • (..) : 파라미터는 상관 없음
@Bean
public Advisor advisor2(LogTrace logTrace) {
// AspectJ 문법을 기반으로 한 AspectJExpressionPointcut
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("execution(* hello.proxy.app..*(..))");

// advice
LogTraceAdvice advice = new LogTraceAdvice(logTrace);

return new DefaultPointcutAdvisor(pointcut, advice);
}

해당 표현식으로 적용하면 no-log 에서도 로그가 찍히는 것을 확인할 수 있다.

2021-12-05 21:47:28.731  INFO 70615 --- [nio-8080-exec-6] h.p.trace.logtrace.ThreadLocalLogTrace   : [afe68ae8] OrderControllerV1Impl.noLog()
2021-12-05 21:47:28.732 INFO 70615 --- [nio-8080-exec-6] h.p.trace.logtrace.ThreadLocalLogTrace : [afe68ae8] OrderControllerV1Impl.noLog() time=1ms

&&|| 등을 이용해 포인트컷 표현식을 다양하게 조합할 수 있습니다.

@Bean
public Advisor advisor3(LogTrace logTrace) {
// Point Cut
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("execution(* hello.proxy.app..*(..)) && !execution(*hello.proxy.app..noLog(..))");

// advice
LogTraceAdvice advice = new LogTraceAdvice(logTrace);

return new DefaultPointcutAdvisor(pointcut, advice);
}

Spring Bean 후처리기 하나의 프록시에 여러개의 Advisor 적용

프록시 자동 생성기

  • Advisor1 의 포인트 컷만 만족
    • 프록시 1개 생성, advisor1 만 포함
  • Advisor1, Advisor2 의 포인트 컷 모두 만족
    • 프록시 1개 생성, advisor1, advisor2 모두 포함
  • Advisor1, Advisor2 의 포인트 컷 모두 만족하지 않음
    • 프록시를 생성하지 않음

하나의 프록시 객체에 여러개의 Advisor 적용

Share