≣ 목차
@Aspect란?
스프링 프레임워크의 AOP(Aspect-Oriented Programming)를 활용하면 여러 클래스에 걸쳐 공통 기능을 효과적으로 적용할 수 있습니다. 이때 핵심 개념인 어드바이저(Advisor)는 포인트컷(Pointcut)과 어드바이스(Advice)로 구성됩니다.
- 포인트컷(Pointcut): 어드바이스를 적용할 메서드를 지정하는 조건입니다. 예를 들어, 특정 패키지의 모든 메서드나 특정 이름을 가진 메서드에 적용할 수 있습니다.
- 어드바이스(Advice): 포인트컷에서 정의한 조건에 맞는 메서드가 실행될 때 수행할 작업입니다.
스프링에서는 @Aspect 애노테이션을 사용해 손쉽게 어드바이저를 생성할 수 있습니다. 이 애노테이션을 클래스에 적용하면 해당 클래스가 AOP의 어드바이저 역할을 수행하게 됩니다.
스프링은 기본적으로 자동 프록시 생성기(AnnotationAwareAspectJAutoProxyCreator)를 생성에 빈으로 등록합니다.
이 자동 프록시 생성기로 스프링은 빈으로 등록된 어드바이저를 찾고 스프링 빈들을 자동으로 프록시를 적용합니다. 물론 포인트컷에 조건이 만족하는 경우 프록시를 생성합니다.
@Aspect를 통해 어드바이저 생성 예제
1 Aspect 클래스 정의
스프링에서 제공하는 @Aspect 애노이테션으로 통해 어드바이저를 쉽게 생성하기 위해서 @Aspect 애노테이션을 가진 클래스를 생성합니다.
@Slf4j
@Aspect
@RequiredArgsConstructor
public class LogTraceAspect {
@Around("execution(* hello.proxy.app..*(..))") // 포인트컷
public Object execute(ProceedingJoinPoint joinPoint) throws Throwable { // 어드바이스
log.info("target={}", joinPoint.getTarget()); //실제 호출 대상(객체)
log.info("getArgs={}", joinPoint.getArgs()); //전달인자(전달 받은 매개변수)
log.info("getSignature={}", joinPoint.getSignature()); //join point 시그니처
log.info("LogTraceAspect.execute() 동작");
Object result = joinPoint.proceed();
return result;
}
}
어드바이저는 두 가지 주요 요소로 구성되어 있습니다: 포인트컷과 어드바이스입니다. 현재 코드에서는 LogTraceAspect가 @Aspect 애노테이션 덕분에 어드바이저 역할을 하고 있으며, @Around 애노테이션은 포인트컷 역할을 수행합니다.
또한, @PointCut 애노테이션을 사용할 수도 있지만, @Around, @Before, @After와 같은 다양한 애노테이션을 통해서도 포인트컷 역할을 수행할 수 있습니다. 추가적으로 위에 코드에서는 AspectJ 표현식을 사용하고 있지만, 패키지 범위나 메소드 이름을 기준으로도 포인트컷을 정의할 수 있습니다.
2 스프링 빈 등록
@Aspect 애노테이션을 통해 어드바이저를 만들었기 때문에, 이를 스프링 빈으로 등록해야 합니다. 왜냐하면 해당 방법은 스프링이 제공하는 자동 프록시 생성기를 사용하기 때문입니다.
@Configuration
public class AopConfig {
@Bean
public LogTraceAspect logTraceAspect() {
return new LogTraceAspect();
}
}
@Aspect를 통해 어드바이저가 만들어지는 과정
- 자동 프록시 생성: 스프링은 애플리케이션이 시작될 때 자동으로 프록시 생성기를 만들어 호출합니다.
- @Aspect 빈 조회: 생성된 프록시 생성기는 스프링 컨테이너에서 @Aspect으로 등록된 빈을 조회합니다.
- 어드바이저 생성: 찾은 빈에서 포인트컷(어떤 메서드에 어드바이스를 적용할지 결정하는 정보)과 어드바이스(실제로 실행할 기능)에 정보를 바탕으로 어드바이저를 생성합니다.
참고로 어드바이저를 생성할 때에는BeanFactoryAspectJAdvisorsBuilder를 통해 생성됩니다.
스프링 AOP를 적용한 프록시 객체 생성 흐름
- 스프링 빈 대상이 되는 객체를 생성
- 생성된 객체를 빈 저장소에 등록하기 직전에 빈 후처리기에 전달되어 추가 작업을 수행하거나 그대로 저장됩니다.
- Advisor 빈 조회
- 스프링 컨테이너에서 모든 Advisor 객체 빈을 조회
- @Aspect 애노테이션이 붙은 클래스를 조회하며, 해당 클래스를 Advisor로 만들어버립니다.
- 3-1, 3-2에서 조회한 Advisor에 PointCut의 조건을 보고 해당 객체가 프록시를 적용할 대상인지 판단합니다. 이때 PointCut 조건에 만족하지 않으면 advice를 적용하지 않고 원래 기능을 수행합니다.
- PointCut 조건에 만족하면 advice를 적용해서 프록시 객체를 생성
- 자동 프록시 생성기에서 반환된 객체를 스프링 빈으로 등록합니다.
어드바이스 적용 순서
스프링 5.2.7 버전부터는 동일한 @Aspect 내에서 조인 포인트에 대해 어드바이스의 우선순위를 정했습니다.
- @Around
- @Before
- @After
- @AfterReturning
- @AfterThrowing
이 순서가 어드바이스가 적용되는 순서입니다. 하지만 호출 순서와 리턴 순서가 다르다는 점을 주의해야 합니다. 즉, 어드바이스가 실행되는 순서와 메서드가 호출된 후 결과를 반환하는 순서는 다릅니다.
그리고 같은 포인트컷을 사용하는 어드바이스가 @Aspect 안에 두 개 이상 있을 경우, 그 실행 순서는 보장되지 않는 문제가 있습니다. 이 문제를 해결하기 위해서는 Aspect클래스를 세분화하여 @Order를 이용해 우선순위를 지정해 해당 문제를 해결할 수 있습니다.
참고
[1] - 스프링 핵심 원리 고급편 - 김영한
[2] - 스프링 공식문서 - https://docs.spring.io/spring-framework/reference/core/aop/ataspectj/advice.html
'Spring' 카테고리의 다른 글
[Spring] Spring AOP 사용 방법 - @Aspect 활용 (0) | 2024.09.27 |
---|---|
[Spring] 스프링 AOP 정리 (0) | 2024.09.26 |
[Spring] 빈 후처리기 (0) | 2024.09.24 |
[Spring] 포인트컷, 어드바이스, 어드바이저 간단 정리 (1) | 2024.09.23 |
[Spring] 스프링 프록시 팩토리 간단 정리 (0) | 2024.09.19 |