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

현시기얌·2021년 11월 27일
0

AOP

목록 보기
8/19

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

build.gradle 추가

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

이 라이브러리를 추가하면 aspectjweaver라는 aspectJ 관련 라이브러리를 등록하고 스프링 부트가 AOP 관련 클래스를 자동으로 스프링 빈에 등록한다.
스프링 부트가 없던 시절에는 @EnableAspectJWutoProxy를 직접 사용해야 했는데 이 부분을 스트림 부트가 자동으로 처리해준다.
스프링 부트가 활성화 하는 빈은 AopAutoConfiguration를 참고하자.

자동 프록시 생성기 - AutoProxyCreator

  • 앞서 이야기한 스프링 부트 자동 설정으로 AnnotationAwareAspectJAutoProxyCreator 라는 빈 후처리기가 스프링 빈에 자동으로 등록된다.
  • 이름 그대로 자동으로 프록시를 생성해주는 빈 후처리기이다.
  • 이 빈 후처리기는 스프링 빈으로 등록된 Advisor들을 자동으로 찾아서 프록시가 필요한 곳에 자동으로 프록시를 적용해준다.
    Advisor 안에는 Pointcut과 Advice가 이미 모두 포함되어 있다. 따라서 Advisor만 알고 있으면 그 안에 있는 Pointcut으로 어떤 스프링 빈에 프록시를 적용해야 할지 알 수 있다.
    그리고 Advice로 부가 기능을 적용하면 된다.

참고

AnnotationAwareAspectJAutoProxyCreator는 @AspectJ와 관련된 AOP 기능도 자동으로 찾아서 처리해준다.
Advisor는 물론이고 @Aspect도 자동으로 인식해서 프록시를 만들고 AOP를 적용해준다.

자동 프록시 생성기의 동작 과정

  1. 생성 : 스프링이 스프링 빈 대상이 되는 객체르르 생성한다. (Bean, 컴포넌트 스캔 모두 포함)
  2. 전달 : 생성된 객체를 빈 저장소에 등록하기 직전에 빈 후처리기에 전달한다.
  3. 모든 Advisor 빈 조회 : 자동 프록시 생성기 - 빈 후처리기는 스프링 컨테이너에서 모든 Advisor를 조회한다.
  4. 프록시 적용 대상 체크 : 앞서 조회한 Advisor에 포함되어 있는 포인트컷을 사용해서 해당 객체가 프록시를 적용할 대상인지 아닌지 판단한다.
    이 때 객체의 클래스 정보는 물론이고, 해당 객체의 모든 메소드를 포인트컷에 하나하나 모두 매칭해본다.
    그래서 조건이 하나라도 만족하면 프록시 적용 대상이 된다.
    예를 들어서 10개의 메소드 중에 하나만 포인트 컷 조건에 만족해도 프록시 적용 대상이 된다.
  5. 프록시 생성 : 프록시 적용 대상이면 프록시를 생성하고 반환해서 프록시를 스프링 빈으로 등록한다.
    만약 프록시 적용 대상이 아니라면 원본 객체를 반환해서 원본 객체를 스프링 빈으로 등록한다.
  6. 빈 등록 : 반환된 객체는 스프링 빈으로 등록된다.

생성된 프록시

프록시는 내부에 Advisor와 실체 호출할 대상 객체(target)을 알고 있다.

예제 코드

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

    @Bean
    public Advisor advisor1(LogTrace logTrace) {
        //pointcut
        final NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
        pointcut.setMappedNames("request*", "order*", "save*");

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

        return new DefaultPointcutAdvisor(pointcut, advice);
    }
}

프록시는 AutoProxyCreator 에서 자동으로 생성해주기 때문에 Advisor만 빈으로 등록하면 된다.

중요 : 포인트 컷은 2가지에 사용된다.

1. 프록시 적용 여부 판단 - 생성 단계

  • 자동 프록시 생성기는 포인트컷을 사용해서 해당 빈이 프록시를 생성할 필요가 있는지 없는지 체크한다.
  • 클래스 + 메소드 조건을 모두 비교한다.
    이때 모든 메소드를 체크하는데 포인트컷 조건에 하나하나 매칭해본다.
    만약 조건에 맞는 것이 하나라도 있으면 프록시를 생성한다.
    ex) orderController에 aaa(),bbb() 가 있다고 가정했을 때 aaa()의 조건에 만족하면 프록시를 생성한다.
  • 만약 조건에 맞는 것이 하나도 없으면 프록시를 생성할 필요가 없으므로 프록시를 생성하지 않는다.

2. Advice 적용 여부 판단 - 사용 단계

  • 프록시가 호출되었을 때 부가 기능은 Advice를 적용할지 말지 포인트컷을 보고 판단한다.
  • 1에서 orderController는 이미 프록시에 걸려있다.
  • orderController의 aaa()는 포인트컷 조건에 만족하므로 프록시는 Advice를 먼저 호출하고 target을 호출한다.
  • orderController의 bbb()는 현재 포인트컷 조건에 만족하지 않으므로 Advice를 호출하지 않고 바로 target을 호출한다.

cf) 참고

프록시를 모든 곳에 생성하는 것은 비용 낭비이다.
꼭 필요한 곳에 최소한의 프록시를 적용해야 한다.
그래서 자동 프록시 생성기는 모든 스프링 빈에 프록시를 적용하는 것이 아니라 포인트컷으로 한번 필터링해서 Advice가 상요될 가능성이 있는 곳에만 프록시를 생성한다.

포인트 컷 주의점

포인트 컷을 정밀하게 설정하지 않으면 기대하지 않았던 부분에도 프록시가 걸릴 수 있다.
따라서 패키지에 메소드 이름까지 함꼐 짖어할 수 있는 매우 정밀한 포인트 컷이 필요하다.

AspectJExpressionPointcut

AspectJ라는 AOP에 특화된 포인트컷 표현식을 적용할 수 있다.

예제 코드

    @Bean
    public Advisor advisor2(LogTrace logTrace) {
        //pointcut
        final AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression("execution(* hello.proxy.app..*(..))");

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

        return new DefaultPointcutAdvisor(pointcut, advice);
    }

execution(* hello.proxy.app..*(..)) : AspectJ가 제공하는 포인트컷 표현식이다.
* : 모든 반환 타입
hello.proxy.app.. : 해당 패키지와 그 하위 패키지
*(..) : * 모든 메소드 이름, (..) : 파라미터는 상관 없음

하나의 프록시 여러 Advisor 적용

예를 들어서 어떤 스프링 빈이 advisor1, advisor2가 제공하는 포인트컷 조건을 모두 만족하면 프록시 자동 생성기는 프록시를 몇개 생성할가?
--> 프록시 자동 생성기는 프록시 하나만 생성한다.
왜냐하면 프록시 팩토리가 생성하는 프록시는 내부에 여러 advisor들을 포함할 수 있기 때문이다.
따라서 프록시를 여러개 생성해서 비용을 낭비할 이유가 없다.

프로깃 자동 생성기 상황별 정리

  • advisor1의 포인트컷만 만족 --> 프록시 1개 생성, 프록시에 advisor1만 포함
  • advisor1, advisor2의 포인트컷을 모두 만족 -> 프록시 1개 생성, 프록시에 advisor1, advisor2 모두 포함
  • advisor1, advisor2의 포인트컷을 모두 만족하지 않음 -> 프록시가 생성되지 않음

정리

자동 프록시 생성기인 AnnotationAwareAspectJAutoProxyCreator 덕분에 개발자는 매우 편리하게 프록시를 적용할 수 있다.
이제 Advisor만 스프링 빈으로 등록하면 된다.
Advisor = Pointcut + Advice

profile
현시깁니다

0개의 댓글