Spring AOP

Spring AOP 강좌 05강 — @Around로 실행 시간 측정 + 예외 처리 Advice

🎯 학습 목표

  • @Around로 메서드 실행 전후를 감싼다.
  • ProceedingJoinPoint로 실제 실행을 제어한다.
  • @AfterReturning / @AfterThrowing으로 결과·예외를 다룬다.

📖 개념 설명

@Around는 대상 메서드의 실행 자체를 감싸므로, 실행 전후 처리는 물론 실행 여부·반환값·예외까지 모두 제어할 수 있는 가장 강력한 Advice입니다. 핵심은 ProceedingJoinPoint.proceed()를 호출해야 실제 대상 메서드가 실행된다는 점입니다.

💻 @Around — 실행 시간 측정

@Aspect
@Component
public class TimerAspect {

    private static final Logger log = LoggerFactory.getLogger(TimerAspect.class);

    @Around("execution(* com.example.service..*(..))")
    public Object measure(ProceedingJoinPoint pjp) throws Throwable {
        long start = System.nanoTime();
        try {
            Object result = pjp.proceed();      // ← 실제 메서드 실행
            return result;                      // 반환값을 그대로(또는 가공해) 돌려줌
        } finally {
            long ms = (System.nanoTime() - start) / 1_000_000;
            log.info("⏱ {} : {}ms", pjp.getSignature().toShortString(), ms);
        }
    }
}

💻 @AfterReturning — 반환값 가로채기

@AfterReturning(
    pointcut = "execution(* com.example.service..find*(..))",
    returning = "result")
public void afterReturn(JoinPoint jp, Object result) {
    log.info("✔ {} 반환값 = {}", jp.getSignature().toShortString(), result);
}

💻 @AfterThrowing — 예외 가로채기

@AfterThrowing(
    pointcut = "execution(* com.example.service..*(..))",
    throwing = "ex")
public void afterThrow(JoinPoint jp, Throwable ex) {
    log.error("✖ {} 예외 발생: {}", jp.getSignature().toShortString(), ex.getMessage());
    // 모니터링 알림, 감사 로그 등에 활용
}

⚠️ 주의사항

  • @Around에서 proceed()를 호출하지 않으면 대상 메서드가 아예 실행되지 않습니다.
  • 반환 타입을 Object로, 시그니처에 throws Throwable을 반드시 선언하세요.
  • @Around는 강력하지만 흐름을 바꿀 수 있어 위험합니다. 단순 전/후 처리는 @Before/@After가 안전합니다.

💡 팁

  • pjp.proceed(newArgs)로 인자를 바꿔 실행할 수도 있습니다(입력 검증·정규화 등).
  • 여러 Aspect가 같은 지점에 적용되면 @Order로 실행 순서를 제어하세요.