If you are familiar with Spring, you’ve probably heard of Aspect Oriented Programming (AOP). That’s one of the main components of the Spring framework.
However, no previous experience in AOP is needed. It is focused for complete beginners who want to understand how AOP framework in Spring works.
In Object Oriented Programming, modularity of an application can be achieved through the usage of Classes. In Aspect Oriented Programming, it is achieved by Aspects. These Aspects allow separation of cross-cutting. In other words, it can add functionality to an already existing code without actually modifying it. In addition, we can declare the new functionality and these new behaviors separately.
Core concepts in AOP
There are 7 core concepts in AOP.
- Business object: normal business logic.
- Aspect: implements enterprise application concerns that cut across multiple classes.
- Join Point: specific point in the application, like variable value, exception handling, method execution, etc.
- Advice: actions taken for a specific join point.
- Pointcut: expressions matched with join points which goal is to determine whether an advice needs to be executed or not.
- Target Object: advices are applied on this.
- AOP proxy: AOP implementation class that uses JDK dynamic proxy to create to create the Proxy classes with target classes and advice calls/invocations.
- Weaving: the process of linking aspects with other objects with the purpose of creating advised proxy objects.
For more information about these concepts, click here.
To implement a Business object class, look below for an example:
public class Example { public String printHelloWorld() { return "Hello World!"; } public String printMessage(String msg) { return msg; } }
This is completely normal class and does not have any Spring-related annotations.
AOP Advice Types
- Before Advice: these advices run before execution of join point methods. To mark an advice type as Before, we can use the @Before annotation.
- After Advice: these advices run after execution of join point methods. To mark an advice type as After, we can use the @After annotation.
- After Returning Advice: these advices run only if the join point method executes normally (meaning no exception). To mark an advice type as After Returning, we can use the @AfterReturning annotation.
- After Throwing Advice: these advices run only when join point method throws exception (the opposite of After Returning Advice). To mark an advice type as After Throwing, we can use the @AfterThrowing annotation.
- Around Advice: these advices give us flexibility because thanks to their usage, we can choose whether to execute a join point method or not.
Let’s see how we can implement those different advice types.
Before Advice
import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; @Aspect public class BeforeAdviceDemo { @Before("com.xyz.demoapp.SystemArchitecture.dataAccessOperation()") public void methodName() { // write code here } }
By using the @Before annotation, we specify that this is a BeforeAdvice.
After Advice
import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; @Aspect public class AfterAdviceDemo{ @After("com.xyz.demoapp.SystemArchitecture.dataAccessOperation()") public void methodName() { // write code here } }
Pretty much like the Before Advice implementation, only we replace the “Before” with “After”.
After Returning Advice
import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; @Aspect public class AfterReturningAdviceDemo{ @AfterReturning("com.xyz.demoapp.SystemArchitecture.dataAccessOperation()") public void methodName() { // write code here } }
Do you see the pattern yet?
After Throwing Advice
import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; @Aspect public class AfterThrowingAdviceDemo { @AfterThrowing("com.xyz.demoapp.SystemArchitecture.dataAccessOperation()") public void methodName() { // write code here } }
Around Advice
The implementation of the Around type is a bit trickier. Since this type of Advice can do work before and after a method executes, it needs to share state before and after that method execution in a thread-safe manner.
To specify that type of Advice, we use the @Around annotation and the first parameter of that advice method must be of type ProceedingJoinPoint. To execute the underlying method, we need to call proceed().
import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.ProceedingJoinPoint; @Aspect public class AroundAdviceDemo { @Around("com.xyz.demoapp.SystemArchitecture.businessService()") public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable { Object value = pjp.proceed(); // return the object return value; } }