- Aspect — the class containing cross-cutting logic (@Aspect).
- Join Point — a specific point in execution, e.g. a method call.
- Advice — the action taken at a join point (Before, After, Around, etc.).
- Pointcut — an expression selecting which join points the advice applies to.
- Weaving — linking aspects to target objects; Spring does this at runtime via proxies.
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);
}
}
}