Contents

Add spring-boot-starter-aop to your dependencies. Spring Boot enables @EnableAspectJAutoProxy automatically.

A @Before advice runs before the matched method executes.

import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; import java.util.Arrays; @Aspect @Component public class LoggingAspect { // Matches all methods in any class under io.cscode.spring.service @Before("execution(* io.cscode.spring.service.*.*(..))") public void logBefore(JoinPoint joinPoint) { System.out.println("Calling: " + joinPoint.getSignature().getName() + " args: " + Arrays.toString(joinPoint.getArgs())); } }

@After runs after the method exits (regardless of outcome). @AfterReturning runs on successful return and can capture the return value. @AfterThrowing runs when an exception is thrown.

import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; @Aspect @Component public class AuditAspect { private static final String PC = "execution(* io.cscode.spring.service.*.*(..))"; @AfterReturning(pointcut = PC, returning = "result") public void logReturn(Object result) { System.out.println("Returned: " + result); } @AfterThrowing(pointcut = PC, throwing = "ex") public void logException(Exception ex) { System.err.println("Exception: " + ex.getMessage()); } @After(PC) public void logFinally() { System.out.println("Method completed (finally)."); } }

@Around is the most powerful advice — it wraps the target method entirely. Use it for timing, caching, transactions, and retry logic.

import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; @Aspect @Component public class TimingAspect { // Applied to any method annotated with @Timed @Around("@annotation(io.cscode.spring.annotation.Timed)") public Object measureTime(ProceedingJoinPoint pjp) throws Throwable { long start = System.currentTimeMillis(); try { return pjp.proceed(); // execute the actual method } finally { long elapsed = System.currentTimeMillis() - start; System.out.printf("%s executed in %d ms%n", pjp.getSignature().toShortString(), elapsed); } } }