
에스팩트
- 애스펙트를 별도의 클래스로 분리해야 한다
- 하나의 애스펙트 안에 있던 어드바이스를 LogAspect , TxAspect 애스펙트로 각각 분리했다. 그리고 각 애스펙트에 @Order 애노테이션을 통해 실행 순서를 적용했다. 참고로 숫자가 작을 수록 먼저 실행된다
@Slf4j
@Aspect
public class AspectV5Order {
@Aspect
@Order(2)
public static class LogAspect {
@Around("hello.aop.order.aop.PointCuts.allOrder()")
public Object doLog(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("[log] {}", joinPoint.getSignature());
return joinPoint.proceed();
}
}
@Aspect
@Order(1)
public static class TxAspect {
@Around("hello.aop.order.aop.PointCuts.allOrderAndAllService()")
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());
throw e;
} finally {
log.info("[리소스 릴리즈] {}", joinPoint.getSignature());
}
}
}
}
- 참고로 클래스 자체에도 사용 가능하고 스프링 빈으로 등록하여 사용 가능
@Slf4j
@Aspect
@Order(1)
public class AspectV1 {
@Around("execution(* hello.aop.order ..*(..))")
public Object doLog(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("[log] {}", joinPoint.getSignature());
return joinPoint.proceed();
}
}
TEST
@Slf4j
@SpringBootTest
@Import({AspectV5Order.LogAspect.class, AspectV5Order.TxAspect.class})
public class AopTest {
@Autowired
OrderService orderService;
@Autowired
OrderRepository orderRepository;
@Test
void aopInfo() {
log.info("isAopProxy, orderService={}",
AopUtils.isAopProxy(orderService));
log.info("isAopProxy, orderRepository={}",
AopUtils.isAopProxy(orderRepository));
}
@Test
void success() {
orderService.orderItem("itemA");
}
@Test
void exception() {
assertThatThrownBy(() -> orderService.orderItem("ex"))
.isInstanceOf(IllegalStateException.class);
}
}

결과
