🎯 학습 목표
- @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로 실행 순서를 제어하세요.