[Spring] @Aspect

Donghoon Jeong·2024년 6월 3일
0

Spring

목록 보기
9/15
post-thumbnail

이전 포스팅에서는 스프링이 제공하는 빈 후처리기인 AnnotationAwareAspectJAutoProxyCreator에 대해 알아보았습니다.

간략하게 요약하자면, 스프링 컨테이너의 빈 저장소에 실제 객체 대신 프록시를 등록하려면 대상 클래스들과 어드바이저를 빈으로 등록하면 됩니다. 그러면AnnotationAwareAspectJAutoProxyCreator가 어드바이저들을 찾아 포인트 컷으로 적용 대상 판별 후 자동으로 프록시를 생성하여 컨테이너 빈 저장소에 등록합니다.

이번 포스팅에서는 직접 어드바이저를 직접 생성하는 것이 아니라 스프링이 제공하는 @Aspect 어노테이션을 활용하여 어드바이저의 생성을 편리하게 해주는 기능을 사용해 보겠습니다.


@Aspect

스프링에서 제공하는 @Aspect 어노테이션은 포인트 컷과 어드바이스로 구성된 어드바이저의 생성을 편리하게 해주는 기능을 가진 어노테이션입니다. 실제 실무에서는 직접 어드바이저를 생성하는 것이 아닌 @Aspect 어노테이션을 이용하여 AOP를 적용합니다.

@Aspect 어노테이션이 붙은 어드바이저를 AOP로 사용하기 위해서는 스프링 빈으로 등록해야 합니다. 하지만 @Aspect 어노테이션은 컴포넌트 스캔의 대상이 아니기 때문에 스프링 컨텍스트에 등록되기 위해서는 @Bean 어노테이션을 사용하여 직접 등록 혹은 @Component 어노테이션을 통해 컴포넌트 스캔의 대상이 되도록 할 수 있습니다.

저번 포스팅에서 자동 프록시 생성기인 AnnotationAwareAspectJAutoProxyCreator는 어드바이저를 기반으로 프록시를 생성한다고 설명하였습니다. 하지만 자동 프록시 생성기의 기능은 이뿐만 아니라 @Aspect 어노테이션을 가진 빈들을 어드바이저로 변환해서 저장하는 기능도 제공합니다.

@Aspect를 어드바이저로 변환해서 저장하는 과정

1. 실행: 스프링 애플리케이션 로딩 시점에 자동 프록시 생성기를 호출합니다.

2. 모든 @Aspect 빈 조회: 자동 프록시 생성기는 스프링 컨테이너에서 @Aspect 어노테이션이 붙은 스프링 빈을 모두 조회합니다.

3. 어드바이저 생성: @Aspect 어드바이저 빌더를 통해 @Aspect 어노테이션 정보를 기반으로 어드바이저를 생성합니다.

4. @Aspect 기반 어드바이저 저장: 생성한 어드바이저를 @Aspect 어드바이저 빌더 내부에 저장합니다.

@Aspect 어드바이저 빌더

BeanFactoryAspectJAdvisorsBuilder 클래스로 @Aspect 어노테이션의 정보를 기반으로 포인트 컷, 어드바이스, 어드바이저를 생성하고 보관하는 것을 담당합니다. @Aspect 어노테이션의 정보를 기반으로 어드바이저를 만들고, @Aspect 어드 바이저 빌더 내부 저장소에 저장합니다. 어드바이저가 이미 만들어져 있는 경우 저장된 어드바이저를 반환합니다.

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

1. 생성: @SpringBootApplication이 실행되며 @Bean과 @Component가 적용된 모든 스프링 빈 대상이 되는 객체를 생성합니다.

2. 전달: 생성된 객체를 빈 저장소에 등록하기 직전에 자동 프록시 생성기(빈 후처리기)에 전달합니다.

3-1. 어드바이저 빈 조회: AnnotationAwareAspectJAutoProxyCreator 는 스프링 컨테이너 내의 모든 어드바이저를 조회합니다.

3-2. @Aspect 어드바이저 조회: @Aspect 어드바이저 빌더 내부에 저장된 어드바이저를 모두 조회합니다.

4. 프록시 적용 대상 체크: 앞서 3-1, 3-2에서 조회한 어드바이저에 포함되어 있는 포인트 컷을 사용해서 해당 객체가 프록시를 적용할 대상인지 아닌지 판단합니다. 이때 객체의 클래스 정보는 물론이고, 해당 객체의 모든 메서드를 포인트 컷에 하나하나 모두 매칭해서 조건이 하나라도 만족하면 해당 클래스는 프록시 적용 대상이 됩니다.

5. 프록시 생성: 프록시 적용 대상이면 프록시를 생성하고 프록시 객체를 반환합니다. 만약 프록시 적용 대상이 아니라면 원본 객체를 반환합니다.

6. 빈 등록: 반환된 객체는 스프링 빈으로 등록됩니다.

구현

@Aspect 어노테이션을 활용해서 어드바이저를 구현하는 방법에 대해서 알아보겠습니다.

@Aspect
public class 클래스명{

    @Around(포인트컷 - AspectJ 표현식)
    public Object 메서드명(ProceedingJoinPoint joinPoint)throws Throwable{

        // 부가기능 로직 작성
        // 부가기능 로직 작성
        // 부가기능 로직 작성

        Object result = joinPoint.proceed();  // 실제 타겟 실행 메서드

        // 부가기능 로직 작성
        // 부가기능 로직 작성
        // 부가기능 로직 작성

		return result;
    }
}

직접 어드바이저를 생성하는 코드와 비교해 보았을 때, 코드의 양이 눈에 띄게 줄어든 것을 확인할 수 있습니다. 기존에는 Pointcut 객체와 MethodInterceptor를 구현하는 Advice 객체를 생성하여 어드바이저 객체에 주입하여 생성해야 했지만, 이제는 @Aspect를 사용하여 자동으로 어드바이저를 생성할 수 있습니다.

  • @Aruond

    포인트 컷 지시자 중 하나로서, 포인트 컷이 만족할 경우 어드바이스 로직(부가기능)을 실행할 위치를 지정해 줍니다.

  • AspectJ 표현식

    포인트 컷 지시자 내부에 표현된 문자열 형식의 표현식으로 프록시 적용 대상을 판별하는 포인트 컷입니다.

    스프링에서는 다양한 포인트 컷을 제공합니다. 하지만 실무에서 가장 많이 사용하는 AspectJ 표현식을 기반으로 사용하는 AspectJExpressionPointcut을 사용합니다.

  • ProceedingJoinPoint joinPoint

    기존 MethodInterceptor를 구현하여 어드바이스를 구현할 때 MethodInvocation invocation과 유사한 역할을 수행합니다. 내부적으로 실제 호출 대상, 호출 메서드, 전달 인자 등의 정보가 들어있습니다.

  • joinPoint.proceed()

    실제 타깃 요청을 위임하는 메서드입니다. @Around 어노테이션 이외의 포인트 컷 지시자를 사용할 경우 실제 타깃의 요청 위임은 자동으로 실행되므로 직접 호출하지 않습니다.

다음 포스팅에서는 AOP의 개념과 스프링에서 AOP가 사용되는 예시를 통해 AOP의 동작 과정을 이해해 보도록 하겠습니다.


Reference

스프링 핵심 원리 - 고급편

profile
정신 🍒 !

0개의 댓글