Spring AOP + AspectJ @Before, @After, @AfterReturning, @AfterThrowing, and @Around Annotation Example
On this page, we will learn how to integrate AspectJ @Before
, @After
, @AfterReturning
, @AfterThrowing
, and @Around
annotation with Spring AOP framework. Spring 2.0 introduced a simpler and more powerful way of writing custom aspects using either a schema-based approach or the AspectJ annotation style.
In the last 5 tutorials, we have used DTD based configuration to create AOP examples which are not recommended by Spring. Before proceeding next, let’s understand what are these annotation do actually and when to use them.
@Aspect – Used to create aspects and it consists all advice.
@Before – Run before the method execution.
@After – Run after the method returned a result.
@AfterReturning – Run after the method returned a result, intercept the returned result as well.
@AfterThrowing – Run after the method throws an exception.
@Around – Run around the method execution.
Technologies Used
Find the list of all technologies used in the example
- Eclipse Oxygen 3
- JDK 8
- Spring 5.0.2.RELEASE
- aspectjweaver.jar
Enabling AspectJ Support
The AspectJ support can be enabled with XML or Java style configuration. In either case, you will also need to ensure that AspectJ’s aspectjweaver.jar
library is on the classpath of your application (version 1.8 or later).
Enabling with Java configuration
To enable AspectJ support with Java @Configuration
add the @EnableAspectJAutoProxy
annotation:
package org.websparrow;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@EnableAspectJAutoProxy
@ComponentScan(basePackages = "org.websparrow")
public class RegisterAspect {
}
Enabling with XML configuration
To enable AspectJ support with XML based configuration uses the aop:aspectj-autoproxy
element:
<aop:aspectj-autoproxy />
Dependencies Required
To resolve the JARs dependency, you can add the following to your pom.xml file.
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.1</version>
</dependency>
</dependencies>
Declaring Aspect
To declare an aspect, we can use @Aspect
annotation at the class level. Classes which declared as aspect will consist the advice.
@Component
@Aspect
public class LogAfterAdvice {
}
Declaring Service
In this example, we have a Bank
service class and it contains deposit(String accountNumber)
method. We want to apply log on the deposit()
method before, after, around, after throwing, and after returning of execution. In all the advice, I have used the same Bank
service class.
package org.websparrow.service;
import org.springframework.stereotype.Service;
@Service
public class Bank {
public String deposit(String accountNumber) {
System.out.println("inside deposit()");
if (accountNumber.equals("YES123")) {
System.out.println("You have successfully deposited your amount to the respective account number.");
return "success";
} else {
throw new InvalidAccountNo();
}
}
}
Declaring Advice
Advice is associated with a pointcut expression, and runs before, after, or around method executions matched by the pointcut. The pointcut expression may be either a simple reference to a named pointcut or a pointcut expression declared in place.
Before Advice
Before advice is declared in an aspect using the @Before
annotation and run before the method execution.
package org.websparrow.aspect;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class LogBeforeAdvice {
@Before("execution(* org.websparrow.service.Bank*.*(..))")
public void logBefore() {
System.out.println(".............I WILL EXECUTE BEFORE DEPOSIT METHOD.............");
}
}
To test it, create a Client
class, call the deposit()
method of Bank
class and pass the YES123
as the account number.
package org.websparrow.client;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.websparrow.RegisterAspect;
import org.websparrow.service.Bank;
public class Client {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(RegisterAspect.class);
ctx.refresh();
Bank bank = ctx.getBean(Bank.class);
bank.deposit("YES123");
}
}
On your console, you will find the logging advice executed first and then deposit()
method will execute.
.............I WILL EXECUTE BEFORE DEPOSIT METHOD.............
inside deposit()
You have successfully deposited your amount to the respective account number.
After Advice
After advice is declared in an aspect using the @After
annotation and run after the method returned a result.
package org.websparrow.aspect;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class LogAfterAdvice {
@After("execution(* org.websparrow.service.Bank*.*(..))")
public void logAfter() {
System.out.println(".............I WILL EXECUTE AFTER DEPOSIT METHOD.............");
}
}
To test it, run Client
class, call the deposit()
method of Bank
class and pass the YES123
as the account number.
On your console, you will find the logging advice executed after the deposit()
method execution.
inside deposit()
You have successfully deposited your amount to the respective account number.
.............I WILL EXECUTE AFTER DEPOSIT METHOD.............
Around Advice
Around advice is declared using the @Around
annotation. The first parameter of the advice method must be of type ProceedingJoinPoint
. Within the body of the advice, calling proceed()
on the ProceedingJoinPoint
causes the underlying method to execute.
package org.websparrow.aspect;
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 LogAroundAdvice {
@Around("execution(* org.websparrow.service.Bank*.*(..))")
public void logAround(ProceedingJoinPoint jp) throws Throwable {
System.out.println(".............I WILL EXECUTE BEFORE DEPOSIT METHOD.............");
jp.proceed();
System.out.println(".............I WILL EXECUTE AFTER DEPOSIT METHOD.............");
}
}
To test it, run the Client
class.
On your console, you will find the logging advice executed before and after the deposit()
method execution.
.............I WILL EXECUTE BEFORE DEPOSIT METHOD.............
inside deposit()
You have successfully deposited your amount to the respective account number.
.............I WILL EXECUTE AFTER DEPOSIT METHOD.............
After Returning Advice
After returning advice runs when a matched method execution returns normally. It is declared using the @AfterReturning
annotation. The name used in the returning
attribute must correspond to the name of a parameter in the advice method. When a method execution returns, the return value will be passed to the advice method as the corresponding argument value.
package org.websparrow.aspect;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class LogAfterReturningAdvice {
@AfterReturning(pointcut = "execution(* org.websparrow.service.Bank*.*(..))", returning = "status")
public void logAfterReturning(Object status) {
System.out.println("\nExecution status of deposit() method is: " + status);
System.out.println(".............I WILL EXECUTE AFTER DEPOSIT METHOD WEHN IT RETURN SOMETHING.............");
}
}
To test it, run the Client
class.
On your console, you will find the logging advice executed after the deposit()
method execution with its return value.
inside deposit()
You have successfully deposited your amount to the respective account number.
Execution status of deposit() method is: success
.............I WILL EXECUTE AFTER DEPOSIT METHOD WHEN IT RETURN SOMETHING.............
After Throwing Advice
After throwing advice runs when a matched method execution exits by throwing an exception. It is declared using the @AfterThrowing
annotation.
package org.websparrow.aspect;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class LogAfterThrowingAdvice {
@AfterThrowing(pointcut = "execution(* org.websparrow.service.Bank*.*(..))", throwing = "ex")
public void logAfterThrowing(Exception ex) {
System.out.println(".............I WILL EXECUTE WHEN ANY EXECEPTION OCCURED.............");
}
}
To test it, run the Client
class, call the deposit()
method of Bank
class and pass the ANY123
as the account number to throw an exception.
On your console, you will find the logging advice executed when the deposit()
method throws an exception.
inside deposit()
.............I WILL EXECUTE WHEN ANY EXECEPTION OCCURED.............
Exception in thread "main" INVALID ACCOUNT NUMBER
at org.websparrow.service.Bank.deposit(Bank.java:18)
at org.websparrow.service.Bank$$FastClassBySpringCGLIB$$4b94fd21.invoke()
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
Download Source Code: spring-aop-aspectj-before-after-afterreturning-afterthrowing-and-around-annotation-example