1. Overview
Spring Aspect Around Advice is the most powerful advice type and runs around a matched method execution. It provides the opportunity to control when and how the actual matching method should execute.
It can also prevent the execution of the target method and return its own custom value to the caller.
Always prefer to use the least powerful advice that meets your requirements. If simple After advice serves your purpose, then use the same.
This Spring Aspect Around advice allows adding any custom functionality before and after the matching method execution. For example, if you want to add logs to the start and end of method executions, then use @Around advice.
2. Spring Aspect Around Advice
We can declare the AspectJ Around advice using the @Around annotation.
@Around(execution("@annotation(Logger)")) public Object logMethodExecution(ProceddingJoinPoint pjp) { String name = pjp.getSignature().getName(); logger.info("Method started : " + name); Object obj = pjp.proceed(); logger.info("Method ended: " + name); return obj; }
In the above code snippet, logMethodExecution is the around advice method annotated with @Around. execution(“@annotation(Logger)”) limits the advice to the methods annotated with @Logger. Whenever any method annotated with @Logger gets called, AOP will intercept and call the logMethodExecution instead.
@Logger public String sayHelloWorld(String name) { return "Hello World " + name; }
AOP intercepts the calls to the above sayHelloWorld method and invokes the Around advice method logMethodExecution.
3. ProceedingJoinPoint is only supported for Around Advice
The first parameter of the Around advice method is the ProceedingJoinPoint. Calling the proceed method of ProceedingJoinPoint will execute the target method. It is completely legal to call proceed method only once, multiple times, or not at all within the body of the Around advice method.
Note that this advice’s return type is Object as the target method may return values of any type. The Advice may return the same result or any custom value back to the caller. In this code, the proceed method retrieves the result from the target method and returned it to the caller.
If the target method doesn’t return any value, then this advice returns null to the caller.
4. Traditional approach without AOP
Spring AOP helps in achieving code reusability without disturbing the target method and separates out the crosscutting concern from the actual implementation. Without Spring AOP feature, every target method needs to be changed as below.
public String sayHelloWorld(String name) { String name = new Object(){}.getClass().getEnclosingMethod().getName(); logger.info("Method started : " + name); String result = "Hello World " + name; logger.info("Method ended: " + name); return result; }
4.1 Proceed methods
ProceedingJoinPoint contains the below proceed methods
- proceed(Object[] args)
- proceed()
The difference between the above two methods lies with how the arguments are passed to the target method. ProceedingJoinPoint encompasses all the arguments passed by the caller. Calling the ProceedingJoinPoint.getArgs method will display all the arguments.
4.1.1 proceed()
When the target method is invoked using the proceed() method, ProceedingJoinPoint will pass all the arguments to the target method internally with no changes. So sayHelloWorld()
will execute with the values passed by the caller. If the caller passes the value “TedBlob”, then sayHelloWorld
method will return the value “Hello World TedBlob”.
@Around(execution("@annotation(Logger)")) public Object logMethodExecution(ProceddingJoinPoint pjp) { Object[] args = pjp.getArgs(); Object obj = pjp.proceed(); return obj; }
4.1.1 proceed(Object[] args)
Using this proceed method, we can change the arguments before passing them to the target method.
@Around(execution("@annotation(Logger)")) public Object logMethodExecution(ProceddingJoinPoint pjp) { Object[] customArgs = new Object[] {"Admin"}; Object obj = pjp.proceed(customArgs); return obj; }
Custom value new Object[] "Admin"
is to the proceed method. So sayHelloWorld()
method will always return "Hello World Admin"
irrespective of the value passed by the caller.
5. Spring AOP Around example
Below are some of the other use cases for Around advice like performance logging, caching the results, and exception handling
5.1 Performance Logger
In the below code snippet, the Advice method calculates the total time taken by the target method to complete its execution and logs it.
@Aspect @Component public class PerformanceLoggerAspect { private Logger logger = Logger.getLogger("performance.logger"); @Around("execute(@annotation(PerformanceLogger))") public Object logPerformance(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { long startTime = System.currentTimeMillis(); try { return proceedingJoinPoint.proceed(); } finally { long finishTime = System.currentTimeMillis(); Duration duration = Duration.ofMillis(finishTime - startTime); logger.info(String.format("Method %s executes for %s", proceedingJoinPoint.getSignature(), duration)); } } }
5.2 Cache
In this code snippet, the Around advice method first checks the cache for the result. If the result is available, then the method fetches the value from the cache and returns it.
If not, then it executes the target method using the proceed method. The method then stores the result in the cache and returns it back to the caller.
@Around("@annotation(Cacheable)") public Object accessCache(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { CacheKey cacheKey = new CacheKey(proceedingJoinPoint); if (cache.containsKey(cacheKey)) { logger.info("Value fetched from the cache " + proceedingJoinPoint.getSignature().getName()); return cache.get(cacheKey); } else { Object result = proceedingJoinPoint.proceed(); cache.put(cacheKey, result); return result; } }
6. Conclusion
In this post, we analyzed the Around advice and its key features. We have also seen few use cases where we can use this advice.
You can refer to our Spring AOP articles to learn further on other topics.