Pull cross-cutting concerns — logging, timing, auditing — out of your business code into reusable aspects that run around your methods automatically.
Why: concerns like logging, timing, and security checks would otherwise be copy-pasted into every method. AOP lets you write that code once in an "aspect" and weave it into many methods by a rule. Note: add spring-boot-starter-aop to enable it.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>Why: @Aspect + @Before runs your code before every matched method. Where: the pointcut expression selects which methods — here, every public method in the service package. Note: JoinPoint gives you the method name and arguments.
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.bookstore.service.*.*(..))")
public void logEntry(JoinPoint jp) {
System.out.println("→ calling " + jp.getSignature().getName());
}
}When @Around: you need to run code before AND after — and control whether the method runs at all. Note: call proceed() to invoke the real method; whatever you return becomes its result. This is how you time methods or add caching.
@Aspect
@Component
public class TimingAspect {
@Around("@annotation(Timed)") // methods annotated @Timed
public Object time(ProceedingJoinPoint jp) throws Throwable {
long start = System.nanoTime();
try {
return jp.proceed(); // run the actual method
} finally {
long ms = (System.nanoTime() - start) / 1_000_000;
System.out.println(jp.getSignature().getName() + " took " + ms + "ms");
}
}
}Note: a pointcut is the rule that picks methods. execution(...) matches by signature; @annotation(...) matches methods carrying an annotation; within(...) matches a whole class or package. Name a pointcut once with @Pointcut and reuse it across advice.
// match by package + signature
@Pointcut("execution(* com.example.bookstore.service.*.*(..))")
void serviceMethods() {}
// match any method annotated with @Timed
@Pointcut("@annotation(com.example.bookstore.Timed)")
void timed() {}
@Before("serviceMethods()") // reuse the named pointcut
public void before() { ... }