@Around Advice & ProceedingJoinPoint
@Around Advice & ProceedingJoinPoint
@Around is the most powerful advice type in Spring AOP. Unlike @Before or @After, which observe method execution from the outside, @Around wraps the entire call. Your advice code runs before the target method, decides whether to invoke it at all, and then runs again after it returns — with full access to the return value and any thrown exception. That control is expressed through a single object: ProceedingJoinPoint.
The Method Signature
An @Around method must declare a ProceedingJoinPoint as its first parameter and must return Object (the advised method's return value, possibly modified).
pjp.proceed() and return its result. If you forget either, the original method never executes (or its return value is silently discarded), which is almost always a bug. The compiler will not warn you — this is a runtime responsibility.
How proceed() Works
pjp.proceed() delegates to the next advice in the chain (or to the real target method if no more advice applies). It propagates any exception thrown by the target, which is why the method signature must declare throws Throwable. You can catch specific exceptions, handle or rethrow them, or swallow them entirely — but swallowing is almost always wrong outside very specific retry patterns.
Inspecting the Join Point
ProceedingJoinPoint exposes rich context about the intercepted call:
pjp.getSignature()— method name, declaring type, return type.pjp.getArgs()— the actual argument values at the time of the call.pjp.getTarget()— the target bean (the object whose method is being called).pjp.getThis()— the proxy itself (rarely needed).
Altering Arguments Before Proceeding
You can replace the argument array before calling proceed(Object[]). The overloaded variant accepts a new argument array, which Spring passes to the target method instead of the originals. This is useful for input sanitisation, normalisation, or injecting audit metadata.
Object[] args = pjp.getArgs().clone()) so that the original array is not mutated in case other aspects inspect it.
Altering the Return Value
Whatever pjp.proceed() returns is just an Object. You can inspect, replace, or wrap it before returning it to the caller. A common use case is caching: check a cache before calling proceed(), and store the result afterward.
Notice that when the cached value exists, proceed() is never called. That is intentional and entirely valid — but document it clearly, because it is invisible to anyone reading only the target method.
Exception Handling Inside @Around
You can catch exceptions thrown by the target and decide what to do:
Practical Timing Aspect: Full Example
Here is a production-grade timing aspect that uses SLF4J, skips fast methods below a threshold, and logs a warning for slow ones:
The finally block guarantees timing is recorded whether the method returns normally or throws. Using System.nanoTime() instead of System.currentTimeMillis() avoids wall-clock jumps caused by NTP adjustments.
Trade-offs and When to Use @Around
- Use
@Aroundwhen you need to measure elapsed time, conditionally skip the method, modify arguments or the return value, or implement retry / fallback logic. - Prefer
@Before/@Afterfor simpler cross-cutting concerns such as logging entry/exit, because they cannot accidentally swallow exceptions or forget to call the target. - Performance:
@Aroundadds one extra method invocation per matched join point. The overhead is typically a few microseconds — negligible except in tight inner loops. Narrow your pointcut to avoid matching hot code paths unnecessarily.
Summary
@Around gives you a complete wrapper around the intercepted method. ProceedingJoinPoint.proceed() hands control to the target; its overload proceed(Object[]) lets you swap arguments first; and the Object return value can be replaced before it reaches the caller. Used correctly — with finally for cleanup, and a clear mental model of what happens when proceed() is not called — @Around is the foundation of logging, timing, caching, retry, and security cross-cutting concerns in production Spring applications.