스프링/스프링 AOP
어드바이스 순서
chanhee01
2023. 9. 22. 20:10
@Order 어노테이션을 이용해서 순서를 줄 수 있다. 그런데 이 어노테이션은 메서드에 부여하는 것이 아니라 클래스에 부여하는 것이다. 클래스 레벨의 @Aspect에 부여되는 것이니 @Aspect 안에 있는 두 개의 메서드에 @Order()를 넣는다해도 순서가 정해지지 않는다.
@Slf4j
public class AspectV5Order {
// hello.aop.order 패키지와 하위 패키지
@Pointcut("hello.aop.order.aop.Pointcuts.allOrder()") // 포인트컷
private void allOrder(){}
// 클래스 이름 패턴이 *Service
@Pointcut("hello.aop.order.aop.Pointcuts.orderAndService()")
private void allService(){}
@Aspect
@Order(2)
public static class LogAspect {
@Around("allOrder()") // allOrder() 메서드를 넣어주면 됨
public Object doLog(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("[log] {}", joinPoint.getSignature()); // joinPoint 시그니처 (메서드 뭐 호출되었는지)
return joinPoint.proceed();
}
}
@Aspect
@Order(1)
public static class TxAspect {
@Around("allOrder() && allService()")
public Object doTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
try {
log.info("[트랜잭션 시작] {}", joinPoint.getSignature());
Object result = joinPoint.proceed();
log.info("[트랜잭션 커밋] {}", joinPoint.getSignature());
return result;
} catch (Exception e) {
log.info("[트랜잭션 롤백] {}", joinPoint.getSignature());
return e;
} finally {
log.info("[리소스 릴리스] {}", joinPoint.getSignature());
}
}
}
}
클래스 안에 클래스를 만들어준다. 전체 클래스 파일 선언부가 아닌 각각의 클래스에 @Aspect 어노테이션을 붙여서 따로 사용되게 해야한다. 그리고 @Order() 어노테이션으로 순서를 부여하는 것이다.
요구사항이 트랜잭션을 실행하는 시간을 제외하고 로그를 찍는 것이라면, 트랜잭션이 1번, 시간로그가 2번이라면 트랜잭션이 실행되는 시간을 제외하고 시간이 찍히는 어드바이스 순서를 지정할 수 있다.
위의 사진을 보면 알겠지만 로직을 수행하고 클라이언트에게로 나갈 때에는 역순으로 나가게 된다.
Service 계층에서는 doTx, doLog 순으로 진행되며 Repository 계층에서는 doTx의 포인트컷에 해당되지 않기에 doLog만 수행하고 이때에는 Order(2)라고 할지라도 첫 번째로 수행된다.