Pointcut Expressions

Common Pointcuts

ExpressionMatches
execution(* com.shopease.service.*.*(..))any method of any class directly in the service package
execution(* com.shopease..*Service.*(..))methods of classes ending in Service, any sub-package
execution(public * *(..))every public method
within(com.shopease.controller..*)all methods inside controller classes
@annotation(com.shopease.aop.Timed)methods annotated with @Timed
bean(orderService)the bean named orderService

Execution syntax: execution(modifiers? returnType declaringType? methodName(params) throws?). * = any one thing, .. = any number (of packages or parameters). Combine with &&, || and !.

Annotation-Driven Pointcuts

A custom annotation is the cleanest way: only methods you mark are advised.

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogExecution {
    String value() default "";
}

@Aspect
@Component
@Slf4j
public class LogExecutionAspect {

    @Around("@annotation(logExecution)")
    public Object log(ProceedingJoinPoint pjp, LogExecution logExecution) throws Throwable {
        String name = logExecution.value().isEmpty() ? pjp.getSignature().getName() : logExecution.value();
        log.info("-> {} args={}", name, Arrays.toString(pjp.getArgs()));
        Object result = pjp.proceed();
        log.info("<- {} result={}", name, result);
        return result;
    }
}

@Service
public class CheckoutService {
    @LogExecution("checkout")
    public OrderResponse checkout(Long cartId) { ... }
}

Practice

Exercise: Write an @AfterThrowing advice that logs every exception thrown from any class in com.shopease.service or its sub-packages.

Show answer
@Aspect
@Component
@Slf4j
public class ErrorLoggingAspect {
    @AfterThrowing(pointcut = "execution(* com.shopease.service..*(..))", throwing = "ex")
    public void logError(JoinPoint jp, Exception ex) {
        log.error("{} failed: {}", jp.getSignature().toShortString(), ex.getMessage());
    }
}