Spring AOP + @AspectJ Annotation Example
March 09, 2023
This page will walk through Spring AOP and @AspectJ
annotation example with @Aspect
, @Pointcut
, @Before
, @After
, @Around
, @AfterReturning
, @AfterThrowing
annotations. AOP stands for Aspect Oriented Programming. The @AspectJ
is a style to declare aspects in a Java class using annotations. To enable @AspectJ
, Spring AOP provides @EnableAspectJAutoProxy
annotation which will be annotated in Java configuration class. To work with Spring AOP and @AspectJ
support, we need to create a class annotated with @Aspect
annotation. In this class we have to create our pointcut and using pointcut we need to create our advice. Spring AOP is used for different purposes such as logging, handling with exception and validating return value of a method.
Here on this page we will provide a complete example to work with Spring AOP and
@AspectJ
support using annotation.
Contents
- 1. Technologies Used
- 2. AOP Terminology
- 3. Project Structure in Eclipse
- 4. Gradle Dependencies
- 5. Configure @EnableAspectJAutoProxy
- 6. @Aspect Annotation
- 7. @Pointcut Annotation
- 8. @Before Advice
- 9. @After Advice
- 10. @Around Advice with ProceedingJoinPoint.proceed()
- 11. @AfterReturning Advice
- 12. @AfterThrowing Advice
- 13. Reference
- 14. Download Source Code
1. Technologies Used
Find the technologies being used in our example.1. Java
2. Spring
3. Eclipse
4. Gradle
2. AOP Terminology
We should know the AOP terminology to work with it.Aspect: Aspect is crosscutting concern. One aspect can lie in multiple objects.
Join point: Join point is a point that represents the execution of a method.
Advice: Advice is an action taken by aspect.
Pointcut: A scenario which matches to join point.
Target object: If an object is advised by more than one aspect, that object is called target object. This is also referred as advised object.
Weaving: Linking aspects to other application objects to create an advised object.
3. Project Structure in Eclipse
Find the project structure in eclipse.4. Gradle Dependencies
Find the Gradle file to resolve JAR dependencies.build.gradle
dependencies { compile 'org.springframework.boot:spring-boot-starter-aop:1.2.7.RELEASE' compile 'org.springframework:spring-aspects:4.1.8.RELEASE' }
5. Configure @EnableAspectJAutoProxy
In java configuration to support @AspectJ, spring provides@EnableAspectJAutoProxy
annotation. We use it as follows.
AspectConfig.java
package com.concretepage; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; @Configuration @EnableAspectJAutoProxy @ComponentScan(basePackages="com.concretepage") public class AspectConfig { }
6. @Aspect Annotation
To create aspect, we need to use@Aspect
annotation at class level. This class will consist all advices. The sample aspect class will look as follows.
@Aspect public class TimeLoggingAspect { }
7. @Pointcut Annotation
To define@Pointcut
annotation, we need to take help of expression. Pointcut is to determine join points of interest. Find some sample poincuts.
1. If we need to apply our advice to all classes of the package com.concretepage.service, do as follows.
@Pointcut(" execution(* com.concretepage.service.*.*(..))")
@Pointcut(" execution (* com.concretepage.bean.UserService.doTask(..))")
UserService
class.
@Pointcut(" execution(* com.concretepage.bean.UserService+.*(..))")
@After
annotation. The method serving as a pointcut expression must have void return type.
@Pointcut(" execution (* com.concretepage.bean.UserService.doTask(..))") public void pointcutDemo() {} @After("pointcutDemo())") public void logdvice(){ }
@AfterThrowing(pointcut = "execution(* com.concretepage.service.*.*(..))", throwing="exception") public void logAfterThrowing(Exception exception){}
@Before("execution(* com.concretepage.service.*.*(..))") public void logBefore(){}
8. @Before Advice
@Before
annotation is used to create before advice. We need to create a method in the aspect class annotated with @Before
and define that method. We defined pointcut with @Before
annotation. The sample use of before advice can be logging before running the method.
TimeLoggingAspect.java
package com.concretepage.aspect; import java.util.Date; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; @Component @Aspect public class TimeLoggingAspect { @Before("execution(* com.concretepage.service.*.*(..))") public void logBefore(){ System.out.println("@Before:"+new Date()); } }
UserService.java
package com.concretepage.service; import org.springframework.stereotype.Service; @Service public class UserService { public Integer multiply(int a, int b){ int res = a*b; System.out.println(a+ "*" + b +"= " + res); return res; } }
SpringAOPTest.java
package com.concretepage; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import com.concretepage.service.UserService; public class SpringAOPTest { public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.register(AspectConfig.class); ctx.refresh(); UserService userService = ctx.getBean(UserService.class); userService.multiply(2, 3); } }
@Before:Tue Dec 15 17:28:38 IST 2015 2*3= 6
9. @After Advice
@After
advice runs just after a method completes it process. It is declared same as @Before
annotation. We need to create a method annotated with @After
in aspect class.
TimeLoggingAspect.java
package com.concretepage.aspect; import java.util.Date; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; @Component @Aspect public class TimeLoggingAspect { @After("execution(* com.concretepage.service.*.*(..))") public void logAfter(){ System.out.println("@After:"+new Date()); } }
SpringAOPTest
and find the output.
2*3= 6 @After:Wed Dec 16 17:49:54 IST 2015
10. @Around Advice with ProceedingJoinPoint.proceed()
Using@Around
annotation, we can achieve the functionality of both @Before
and @After
advice. For this we need to create a method annotated with @Around
in aspect class. Inside this method use ProceedingJoinPoint.proceed()
and before and after of this line, write your advice like logging.
TimeLoggingAspect.java
package com.concretepage.aspect; import java.util.Date; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; @Component @Aspect public class TimeLoggingAspect { @Around("execution(* com.concretepage.service.*.*(..))") public void userAdvice(ProceedingJoinPoint joinPoint) throws Throwable{ System.out.println("@Around: Before calculation-"+ new Date()); joinPoint.proceed(); System.out.println("@Around: After calculation-"+ new Date()); } }
@Around: Before calculation-Thu Dec 17 11:47:20 IST 2015 2*3= 6 @Around: After calculation-Thu Dec 17 11:47:20 IST 2015
11. @AfterReturning Advice
@AfterReturning
annotation is used to create after returning advice. @AfterReturning
has attribute as returning which can be used to get retuned data from a method which is covered by defined pointcut with @AfterReturning
annotation.
TimeLoggingAspect.java
package com.concretepage.aspect; import java.util.Date; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; @Component @Aspect public class TimeLoggingAspect { @AfterReturning(pointcut = "execution(* com.concretepage.service.*.*(..))", returning="val") public void logAfterReturning(Object val){ System.out.println("Method return value:"+ val); System.out.println("@AfterReturning:"+new Date()); } }
2*3= 6 Method return value:6 @AfterReturning:Wed Dec 16 20:58:41 IST 2015
12. @AfterThrowing Advice
Using AOP we can also create an advice which will run just after throwing any exception. For this we need to use@AfterThrowing
annotation to define our advice in aspect class. To work with exception, @AfterThrowing
has an attribute as throwing.
TimeLoggingAspect.java
package com.concretepage.aspect; import java.util.Date; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; @Component @Aspect public class TimeLoggingAspect { @AfterThrowing(pointcut = "execution(* com.concretepage.service.*.*(..))", throwing="exception") public void logAfterThrowing(Exception exception){ System.out.println("@AfterReturning:"+new Date()); System.out.println("Exception caught:"+ exception.getMessage()); } }
UserService
, in which we are dividing a number by another number.
UserService.java
package com.concretepage.service; import org.springframework.stereotype.Service; @Service public class UserService { public Integer devide(int a, int b){ int res = a/b; System.out.println(a+ "/" + b +"= " + res); return res; } }
SpringAOPTest
, we need to use below line.
UserService userService = ctx.getBean(UserService.class); userService.devide(5,0);
@AfterThrowing
. Find the output.
@AfterReturning:Thu Dec 17 11:31:32 IST 2015 Exception caught:/ by zero Exception in thread "main" java.lang.ArithmeticException: / by zero at com.concretepage.service.UserService.devide(UserService.java:6)