Careeroza
Advice Types
Five Kinds of Advice
| Annotation | Runs | Typical use |
|---|---|---|
@Before | before the method | validation, audit "attempt" logs |
@AfterReturning | after a normal return (can read the result) | audit success, metrics |
@AfterThrowing | after an exception (can read it) | alerting, error metrics |
@After | always, like finally | cleanup, MDC clear |
@Around | wraps the call; you decide whether to call proceed() | timing, retries, caching |
All Advice Types Together
@Aspect
@Component
@Slf4j
public class OrderAuditAspect {
@Pointcut("execution(* com.shopease.service.OrderService.placeOrder(..))")
void placeOrder() {}
@Before("placeOrder() && args(request)")
public void before(PlaceOrderRequest request) {
log.info("Order attempt by user {}", request.userId());
}
@AfterReturning(pointcut = "placeOrder()", returning = "order")
public void success(OrderResponse order) {
log.info("Order {} placed, total {}", order.id(), order.total());
}
@AfterThrowing(pointcut = "placeOrder()", throwing = "ex")
public void failure(Exception ex) {
log.error("Order failed: {}", ex.getMessage());
}
@After("placeOrder()")
public void always() {
MDC.clear();
}
}Example
curl -X POST localhost:8080/api/orders -H "Content-Type: application/json" -d '{"userId":7,"items":[{"productId":3,"quantity":1}]}'Example output
INFO OrderAuditAspect : Order attempt by user 7 INFO OrderAuditAspect : Order 1001 placed, total 54999.00
Ordering Several Aspects
When several aspects match the same method, put @Order on the aspect classes: the lower number runs first on the way in and last on the way out.
request -> SecurityAspect(@Order 1) -> TimingAspect(@Order 2) -> OrderService.placeOrder() response <- SecurityAspect <- TimingAspect <- return value