Aspect-Oriented Programming (AOP)
@Transactional, @Async, and @PreAuthorize all secretly work the same way underneath. This module is that shared mechanism itself — and how to write your own cross-cutting behavior using it directly.
Learning objectives
- Beginner: Explain what a 'cross-cutting concern' is and name three examples already seen elsewhere in this course.
- Intermediate: Write a custom @Aspect that logs the execution time of any method annotated with a custom annotation.
- Advanced: Explain the difference between @Before, @After, and @Around advice, and why only @Around can change a method's return value.
◆ The problem
Logging method entry/exit, checking authorization, measuring execution time, and wrapping a transaction all need to happen around MANY unrelated methods across the codebase — none of that logic belongs inside the business logic itself, yet it needs to run alongside almost every method.
This is what "cross-cutting concern" means: behavior that cuts across many classes' core responsibilities rather than belonging to any one of them. @Transactional (Module 23), @Async (Module 25), and @PreAuthorize (Spring Security category) are all real examples already covered — each one injects behavior around a method without that method's own code needing to know about it.
AOP (Aspect-Oriented Programming) is the general framework underneath ALL of those annotations — Spring AOP creates a proxy around any bean that has matching "advice" applied to it, and that proxy intercepts calls exactly the way this course has already described three separate times for three separate annotations.
◆ Under the hood
This is precisely why the self-invocation bug appears identically for @Transactional, @Async, and @PreAuthorize — all three are just built-in Spring AOP aspects, sharing the exact same proxy-based interception mechanism, and therefore sharing the exact same limitation.
@Aspect @Component public class ExecutionTimeAspect { @Around("@annotation(LogExecutionTime)") public Object logTime(ProceedingJoinPoint joinPoint) throws Throwable { long start = System.currentTimeMillis(); Object result = joinPoint.proceed(); // actually runs the real method long duration = System.currentTimeMillis() - start; log.info("{} took {}ms", joinPoint.getSignature(), duration); return result; } }
joinPoint.proceed() is the moment control passes to the real method — everything before it is "before" behavior, everything after is "after" behavior, and @Around advice is the only type that can inspect or even completely replace the method's return value.
💻 Code example
@Aspect @Component public class ExecutionTimeAspect { @Around("@annotation(LogExecutionTime)") public Object logTime(ProceedingJoinPoint joinPoint) throws Throwable { long start = System.currentTimeMillis(); Object result = joinPoint.proceed(); long duration = System.currentTimeMillis() - start; log.info("{} took {}ms", joinPoint.getSignature(), duration); return result; } }
| Advice type | Runs | Can change the return value? |
|---|---|---|
| @Before | Just before the method | No |
| @After | Just after the method (success or failure) | No |
| @AfterReturning | Just after a successful return | No (can inspect it, not replace it) |
| @AfterThrowing | Only if the method threw | No |
| @Around | Wraps the ENTIRE call | Yes — it explicitly decides whether/how to call the real method at all |
@Around is the most powerful and the most dangerous — forgetting to call joinPoint.proceed() inside one silently skips the real method entirely, with no error to indicate why.
✓ Quick recap
- A cross-cutting concern is behavior needed across many unrelated methods (logging, transactions, security, timing).
@Transactional,@Async, and@PreAuthorizeare all built on the same Spring AOP proxy mechanism this module makes explicit.@Aroundadvice wraps the whole call and is the only type that can change the return value — but forgettingproceed()silently skips the real method.
Want a visual for this concept?
Generate a diagram tailored to “Aspect-Oriented Programming (AOP)” — the AI picks whichever visual (flowchart, comparison, sequence, etc.) best fits.
Sign in to generate a visual →