What is Aspect, Advice, Pointcut, Join Point?
4. @Order -> execution order 5. getArgs() -> array copy, be careful 6. @Around -> do not forget proceed()
Junior Level
AOP Terms:
| Term | What it means | Example |
|---|---|---|
| Join Point | Specific method to intercept | UserService.save() |
| Pointcut | Rule WHERE to apply | “All methods with @Transactional” |
| Advice | WHAT to do (logic) | “Log execution time” |
| Aspect | Module combining Pointcut + Advice | Logging class |
@Aspect
@Component
public class LoggingAspect { // Aspect
@Around("@annotation(LogTime)") // Pointcut
public Object logTime(ProceedingJoinPoint pjp) { // Advice
long start = System.currentTimeMillis();
try {
return pjp.proceed(); // Join Point call
} finally {
log.info("Completed in " + (System.currentTimeMillis() - start) + "ms");
}
}
}
Middle Level
Types of Advice
@Before("pointcut")
public void before() { } // Before method
@After("pointcut")
public void after() { } // After method (always)
// @After = like finally, executes ALWAYS (on success and on exception)
// @AfterReturning = only if method completed SUCCESSFULLY (no exceptions)
@AfterReturning(pointcut = "pc", returning = "result")
public void afterReturn(Object result) { } // After successful
@AfterThrowing(pointcut = "pc", throwing = "ex")
public void afterThrow(Exception ex) { } // On exception
@Around("pointcut")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
// Before
Object result = pjp.proceed(); // Method call
// After
return result;
}
Static vs Dynamic Pointcuts
Static (fast):
-> Checked once during bean creation
-> By annotations, signature, method name
Dynamic (slow):
-> Checked on EVERY call
-> By argument values
-> Overhead on each check
Senior Level
JoinPoint Information
@Around("pointcut")
public Object log(ProceedingJoinPoint pjp) {
pjp.getSignature(); // Method signature
pjp.getArgs(); // Arguments (array copy!)
pjp.getTarget(); // Original object
pjp.getThis(); // Proxy
// getArgs() creates a copy of the array -> GC pressure (noticeable only on very frequent aspect calls - hundreds of thousands per second - or with large argument arrays).
}
Aspect = Singleton
// Aspect is Singleton by default!
// -> Do NOT store state in aspect fields!
@Aspect
public class MetricsAspect {
// Not thread-safe!
private int callCount = 0;
// ThreadLocal
private ThreadLocal<Long> startTime = new ThreadLocal<>();
}
Pipeline
ReflectiveMethodInvocation:
1. Finds all Advisors
2. Filters by Pointcut
3. Sorts by @Order
4. Creates List<MethodInterceptor>
5. Recursively goes through all
6. Calls target.invoke()
Production Experience
Real scenario: Around without proceed
@Around("@annotation(Cacheable)")
public Object cache(ProceedingJoinPoint pjp) {
if (cache.has(key)) return cache.get(key);
// Forgot pjp.proceed()!
// -> Method is NEVER called!
}
Best Practices
- Static Pointcut -> faster
- Narrow Pointcut -> less overhead. The more precise the pointcut, fewer beans will be proxied and fewer checks on each method call.
- No state in aspects (Singleton!)
- @Order -> execution order
- getArgs() -> array copy, be careful
- @Around -> do not forget proceed()
Summary for Senior
- Join Point = call context
- Pointcut = method filter
- Advice = injection type
- Aspect = logical module
- Pipeline = interceptor chain
- Aspect = Singleton -> no state
- proceed() -> required in @Around
Interview Cheat Sheet
Must know:
- Join Point = specific method, Pointcut = filter (where), Advice = logic (what), Aspect = module
- 5 Advice types: @Before, @After, @AfterReturning, @AfterThrowing, @Around
- @After executes ALWAYS (like finally), @AfterReturning - only on success
- Static Pointcuts checked once during bean creation, dynamic - on each call
- Aspect = Singleton -> do NOT store state in fields, use ThreadLocal
- pjp.proceed() required in @Around - otherwise method will not be called
- Pipeline: ReflectiveMethodInvocation filters Advisors by Pointcut, sorts by @Order, goes recursively
- getArgs() creates array copy -> GC pressure on frequent calls
Common follow-up questions:
- @After vs @AfterThrowing - when to use which? -> @After = resource cleanup always, @AfterThrowing = error handling
- Why is aspect = Singleton? -> Spring registers aspects as regular beans (Singleton by default)
- Static vs dynamic Pointcut - which to choose? -> Static is faster, dynamic is more flexible; prefer static
- What happens if you forget pjp.proceed()? -> Original method will not execute at all
Red flags (DO NOT say):
- “@After only on success” - that is @AfterReturning
- “Aspect storing state is fine” - Singleton, not thread-safe
- “Dynamic Pointcut is faster” - opposite, checked every time
- “getArgs() returns the original array” - creates a copy
Related topics:
- [[15. What is AOP Aspect-Oriented Programming]]
- [[13. What is a proxy in Spring]]
- [[17. What does the Transactional annotation do]]
- [[18. Why Transactional does not work with self-invocation]]