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 consist 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

  1. Eclipse Oxygen 3
  2. JDK 8
  3. Spring 5.0.2.RELEASE
  4. 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 use 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.

Bank.java
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.

LogBeforeAdvice.java
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.

Client.java
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");

	}
}
Output:

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.

LogAfterAdvice.java
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.

Output:

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.

LogAroundAdvice.java
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.

Output:

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.

LogAfterReturningAdvice.java
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.

Output:

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.

LogAfterThrowingAdvice.java
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.

Output:

On your console, you will find the logging advice executed when the deposit() method throw 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)

References

  1. @AspectJ support

Share this article on: