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
@Pointcut (
value
= "execution(* com.examples.service.GeneralService.*(..))" )
private void
logDisplay()
{
}
@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
@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
@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
@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
@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:
pom.xml
XML
<? xml version = "1.0" encoding = "UTF-8" ?>
< 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 >
< dependency >
< groupId >org.springframework.boot</ groupId >
< artifactId >spring-boot-starter-aop</ artifactId >
</ dependency >
< 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
public class DifferentAdviceExampleApplication {
public static void main(String[] args)
{
ConfigurableApplicationContext context
= SpringApplication.run(
DifferentAdviceExampleApplication. class ,
args);
GeneralService service
= context.getBean(GeneralService. class );
String employeeNumber = "A123" ;
try {
service.checkEmployeeExistence(employeeNumber);
}
catch (Exception ex) {
System.out.println( "Exception occurred.."
+ ex.getMessage());
}
String accnumber = "10000" ;
try {
service.getBalance(accnumber);
}
catch (Exception ex) {
System.out.println( "Exception occurred.."
+ ex.getMessage());
}
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;
@Aspect
@Component
public class DifferentAspect {
@Pointcut (
value
= "execution(* com.examples.service.GeneralService.*(..))" )
private void
logDisplay()
{
}
@Before (
"execution(* com.examples.service.GeneralService.*(..))" )
public void
logBefore()
{
System.out.println(
".............I WILL EXECUTE BEFORE EACH AND EVERY METHOD............." );
}
@After (
"execution(* com.examples.service.GeneralService.*(..))" )
public void
logAfter()
{
System.out.println(
".............I WILL EXECUTE AFTER EACH AND EVERY METHOD............." );
}
@AfterReturning (
value
= "execution(* com.examples.service.GeneralService.*(..))" ,
returning = "account" )
public void
afterReturningAdvice(JoinPoint joinPoint)
{
System.out.println( "After Returning method:"
+ joinPoint.getSignature());
}
@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());
}
@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." );
}
}
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:
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
String accnumber = null ;
try {
service.getBalance(accnumber);
}
catch (Exception ex) {
System.out.println( "Exception occurred.."
+ ex.getMessage());
}
|
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
Whether you're preparing for your first job interview or aiming to upskill in this ever-evolving tech landscape,
GeeksforGeeks Courses are your key to success. We provide top-quality content at affordable prices, all geared towards accelerating your growth in a time-bound manner. Join the millions we've already empowered, and we're here to do the same for you. Don't miss out -
check it out now!
Last Updated :
12 Dec, 2022
Like Article
Save Article