Aspect-oriented programming
AOP handles cross-cutting concerns such as logging, security, transactions, metrics and caching in one place, instead of scattering them across every method.
Vocabulary:
- Aspect: the class holding the cross-cutting logic (
@Aspect). - Advice: what runs and when:
@Before,@AfterReturning,@AfterThrowing,@After,@Around. - Pointcut: where it applies, such as
execution(* com.app.service..*(..))or@annotation(...). - Join point: a method execution being intercepted.
You already use AOP every day: @Transactional, @Cacheable, @Async and @PreAuthorize are all aspects.
Example
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogTime {}
@Aspect
@Component
public class TimingAspect {
private static final Logger log = LoggerFactory.getLogger(TimingAspect.class);
@Around("@annotation(com.javaatlas.LogTime)")
public Object time(ProceedingJoinPoint pjp) throws Throwable {
long start = System.nanoTime();
try {
return pjp.proceed(); // call the real method
} finally {
long ms = (System.nanoTime() - start) / 1_000_000;
log.info("{} took {} ms", pjp.getSignature().toShortString(), ms);
}
}
}
@Service
class ReportService {
@LogTime
public Report monthly() { /* ... */ return new Report(); }
}Common mistake
Expecting an aspect to run when a method is called from inside the same class. That call bypasses the proxy.
Under the hood
Spring AOP is proxy-based: JDK dynamic proxies for interfaces, CGLIB subclass proxies otherwise (Spring Boot's default). So it only intercepts calls that come through the proxy, never self-invocation, and it can't advise final methods or classes. Full AspectJ weaving at compile or load time removes these limits but is rarely needed.
Check yourself
Which of these is a cross-cutting concern?
How this connects
Know these first
Where this leads
You've reached the end of this thread. Try a learning path for what's next.
Was this lesson helpful?
Finished reading? Mark it complete to track your progress.