Open In App

Usage of @Before, @After, @Around, @AfterReturning, and @AfterThrowing in a Single Spring AOP Project

Last Updated : 12 Dec, 2022
Improve
Improve
Like Article
Like
Save
Share
Report

Spring AOP has come up with different annotations namely  @Before, @After, @Around,@AfterReturning, and @AfterThrowing. Usually, confusions occur among developers were to write the apt code among these annotations. In this article, let us see them by using a sample application. 

@Around

This is the most effective advice among all other advice. The first parameter is of type ProceedingJoinPoint. Code should contain proceed() on the ProceedingJoinPoint and it causes the underlying lines of code to execute. It contains the code that has to be executed before and after when the method is matched with the pointcut

Sample snippet

Main important thing is that even if there are @Before annotations, @Around will be invoked first with the before invocation and then only @Before will be called.

Java




// Displays all the available methods i.e. the advice will
// be called for all the methods The method declaration is
// called the pointcut signature. It provides a name that can
// be used by advice annotations to refer to that pointcut.
@Pointcut(
    value
    = "execution(* com.examples.service.GeneralService.*(..))")
private void
logDisplay()
{
}
 
// Declares the around advice that is applied before and
// after the method matching with a pointcut expression Even
// there are @Before annotations, @Around will be invoked
// first with the before invocation and then only @Before
// will be called
@Around(value = "logDisplay()")
public void aroundAdvice(ProceedingJoinPoint jp)
    throws Throwable
{
    System.out.println(
        "The method aroundAdvice() before invocation of the method "
        + jp.getSignature().getName() + " method");
    try {
        jp.proceed();
    }
    finally {
    }
    System.out.println(
        "The method aroundAdvice() after invocation of the method "
        + jp.getSignature().getName() + " method");
}


Hence this is always an ideal and good place to perform the business logic and it will help to inform what is happening before and after the application when the code runs.

Possible Use-cases

  • When the user is downloading an image in an application
  • When an employee logs in into the office on daily basis.
  • When an external application like a printer/scanner started its job in the specified time etc.

In all these scenarios, @Around advice helps to provide the logs before and after, and also the service also runs perfectly.

@Before 

This advice will run as a first step if there is no @Around advice. If @Around is there, it will run after the beginning portion of @Around.

Sample snippet

Java




// If there is no @Around advice, @Before will be called
// first, otherwise @Around Before Invocation is called
@Before(
    "execution(* com.examples.service.GeneralService.*(..))")
public void
logBefore()
{
 
    System.out.println(
        ".............I WILL EXECUTE BEFORE EACH AND EVERY METHOD.............");
}


Possible scenario to have @Before:

For example, if there are two tables(parent and child) and when there is an insert happening in the child table, we need to check whether already the corresponding parent exists or not. It can be checked with @Before 

@After

This advice will run as a step after @Before advice if there is no @Around advice. If @Around is there, it will run after the ending portion of @Around.

Sample snippet

Java




// If there is no @Around advice, @After will be called
// after @Before(if available) first, otherwise @Around After
// Invocation is called
@After(
    "execution(* com.examples.service.GeneralService.*(..))")
public void
logAfter()
{
    System.out.println(
        ".............I WILL EXECUTE AFTER EACH AND EVERY METHOD.............");
}


Possible scenario to have @After:

For example, if an image or an mp4 is getting downloaded, we need to inform the end-users about the download process is complete. They are all handled at @After 

@AfterReturning

This advice will run as a step after @After advice. Usually, this is the place , where we need to inform about the successful resultant of the method. If the method successSnippetfully returned back, @AfterReturning will have a place to indicate the results.

Sample Snippet:

Java




// implementing after returning advice
// This is generally used to indicate the output after
// successful return of the method, will be called at last
// i.e. after @Around
@AfterReturning(
    value
    = "execution(* com.examples.service.GeneralService.*(..))",
    returning = "account")
public void
afterReturningAdvice(JoinPoint joinPoint)
{
    System.out.println("After Returning method:"
                       + joinPoint.getSignature());
}


Possible scenario to have @AfterReturning:

The result of the method either success/failure, its root causes, and the final result are all can be mentioned here.

@AfterThrowing

This step will be executed whenever there is an exception in the code. We need to handle that by putting try-catch blocks and always it is a good practice to handle exceptions. In AOP, by means of @AfterThrowing, it is handled.

Sample snippet:

Java




// implementing after throwing advice
// This is generally used to indicate the exception in case
// of exception , will be called whenever exception occurs
@AfterThrowing(
    value
    = "execution(* com.examples.service.GeneralService.*(..))",
    throwing = "ex")
public void
afterThrowingAdvice(JoinPoint joinPoint, Exception ex)
{
    System.out.println("After Throwing exception in method:"
                       + joinPoint.getSignature());
    System.out.println("Exception is:" + ex.getMessage());
}


Possible scenario to have @AfterThrowing:

Whenever there are Checked exceptions like IOExceptions (File not found when trying to download) or Unchecked exceptions like Arithmetic Exception (division by zero due to some calculations), this is the place where the code will enter and perform the steps which are present here.

By combining all the above advice, let us build a sample maven project to hold all advice. 

Example Project

Project structure:

Project structure

 

pom.xml

XML




<?xml version="1.0" encoding="UTF-8"?>
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                             https://maven.apache.org/xsd/maven-4.0.0.xsd">
   
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/>
    </parent>
    <groupId>com.examples</groupId>
    <artifactId>aop-different-advice-example</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>aop-around-advice-example</name>
    <description>Demo project for Spring Boot</description>
 
    <properties>
        <java.version>1.8</java.version>
    </properties>
 
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
       
          <!-- This is the much required dependency to have various advices -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
       
        <!-- For testing -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
 
</project>


Let us see the java part

DifferentAdviceExampleApplication.java

Java




import com.examples.service.GeneralService;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
 
@SpringBootApplication
// @EnableAspectJAutoProxy annotation enables support for
// handling the components marked with @Aspect annotation.
@EnableAspectJAutoProxy
public class DifferentAdviceExampleApplication {
    public static void main(String[] args)
    {
        ConfigurableApplicationContext context
            = SpringApplication.run(
                DifferentAdviceExampleApplication.class,
                args);
        // Fetching the  object from the application
        // context.
        GeneralService service
            = context.getBean(GeneralService.class);
        // checking for an employee available in the
        // organization
        String employeeNumber = "A123";
        try {
            service.checkEmployeeExistence(employeeNumber);
        }
        catch (Exception ex) {
            System.out.println("Exception occurred.."
                               + ex.getMessage());
        }
        // Displaying balance in the account.
        String accnumber = "10000";
        try {
            service.getBalance(accnumber);
        }
        catch (Exception ex) {
            System.out.println("Exception occurred.."
                               + ex.getMessage());
        }
        // Closing the context object.
        context.close();
    }
}


DifferentAspect.java

Java




import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
 
// Enables the spring AOP functionality in an application
@Aspect
@Component
public class DifferentAspect {
    // Displays all the available methods i.e. the advice
    // will be called for all the methods The method
    // declaration is called the pointcut signature. It
    // provides a name that can be used by advice annotations
    // to refer to that pointcut.
    @Pointcut(
        value
        = "execution(* com.examples.service.GeneralService.*(..))")
    private void
    logDisplay()
    {
    }
    // If there is no @Around advice, @Before will be called
    // first, otherwise @Around Before Invocation is called
    @Before(
        "execution(* com.examples.service.GeneralService.*(..))")
    public void
    logBefore()
    {
 
        System.out.println(
            ".............I WILL EXECUTE BEFORE EACH AND EVERY METHOD.............");
    }
    // If there is no @Around advice, @After will be called
    // after @Before(if available) first, otherwise @Around
    // After Invocation is called
    @After(
        "execution(* com.examples.service.GeneralService.*(..))")
    public void
    logAfter()
    {
        System.out.println(
            ".............I WILL EXECUTE AFTER EACH AND EVERY METHOD.............");
    }
 
    // implementing after returning advice
    // This is generally used to indicate the output after
    // successful return of the method, will be called at
    // last i.e. after @Around
    @AfterReturning(
        value
        = "execution(* com.examples.service.GeneralService.*(..))",
        returning = "account")
    public void
    afterReturningAdvice(JoinPoint joinPoint)
    {
        System.out.println("After Returning method:"
                           + joinPoint.getSignature());
        // System.out.println(account);
    }
 
    // implementing after throwing advice
    // This is generally used to indicate the exception in
    // case of exception , will be called whenever exception
    // occurs
    @AfterThrowing(
        value
        = "execution(* com.examples.service.GeneralService.*(..))",
        throwing = "ex")
    public void
    afterThrowingAdvice(JoinPoint joinPoint, Exception ex)
    {
        System.out.println(
            "After Throwing exception in method:"
            + joinPoint.getSignature());
        System.out.println("Exception is:"
                           + ex.getMessage());
    }
 
    // Declares the around advice that is applied before and
    // after the method matching with a pointcut expression
    // Even there are @Before annotations, @Around will be
    // invoked first with the before invocation and then only
    // @Before will be called
    @Around(value = "logDisplay()")
    public void
    aroundAdvice(ProceedingJoinPoint proceedingJoinPoint)
        throws Throwable
    {
        System.out.println(
            "The method aroundAdvice() before invocation of the method "
            + proceedingJoinPoint.getSignature().getName()
            + " method");
        try {
            proceedingJoinPoint.proceed();
        }
        finally {
        }
        System.out.println(
            "The method aroundAdvice() after invocation of the method "
            + proceedingJoinPoint.getSignature().getName()
            + " method");
    }
}


GeneralService.java

Java




import org.springframework.stereotype.Service;
 
@Service
public class GeneralService {
    public void getBalance(String accNum)
    {
        System.out.println("Inside getBalance() method");
        if (accNum.equals("12345")) {
            System.out.println("Total balance: ......");
        }
        else {
            System.out.println(
                "Sorry! wrong account number.");
        }
    }
 
    // second method
    // we can write any methods and when called, all methods
    // follow the same flow
    public String
    checkEmployeeExistence(String employeeNumber)
    {
        System.out.println(
            "Inside checkEmployeeExistence() method");
        String status = null;
        if (employeeNumber.equals("A123")) {
            System.out.println(employeeNumber
                               + " is currently active");
            status = "active";
        }
        else {
            System.out.println(employeeNumber
                               + " is currently inactive");
            status = "Inactive";
        }
        return status;
    }
}


Program execution and output:

 

Output:

Output

 

Explanation:

1. checkEmployeeExistence method
// @around advice begins
The method aroundAdvice() before invocation of the method checkEmployeeExistence method

// @before advice 
.............I WILL EXECUTE BEFORE EACH AND EVERY METHOD.............

// execution steps
Inside checkEmployeeExistence() method
A123 is currently active

// @around advice ends
The method aroundAdvice() after invocation of the method checkEmployeeExistence method

// @after advice 
.............I WILL EXECUTE AFTER EACH AND EVERY METHOD.............
@afterreturning
After Returning method:String com.examples.service.GeneralService.checkEmployeeExistence(String)

// Similarly it will be done for getBalance

Let us see when an exception throws for getBalance method by just passing accountnumber to null

Java




// Displaying balance in the account.
String accnumber = null;
try {
    service.getBalance(accnumber);
}
catch (Exception ex) {
    System.out.println("Exception occurred.."
                       + ex.getMessage());
}


Output

 

Explanation:

// @around advice begins
The method aroundAdvice() before invocation of the method getBalance method
@before advice
.............I WILL EXECUTE BEFORE EACH AND EVERY METHOD.............
// execution steps
Inside getBalance() method

// An exception is occurred and hence it will come out and print data from @after advice 
.............I WILL EXECUTE AFTER EACH AND EVERY METHOD.............

@AfterThrowing advice
After Throwing exception in method:void com.examples.service.GeneralService.getBalance(String)
Exception is:Cannot invoke "String.equals(Object)" because "accNum" is null
Exception occurred..Cannot invoke "String.equals(Object)" because "accNum" is null


Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads