In this post, We will learn about the Spring AOP AfterReturning and AfterThrowing Advice Example using a Demo Project.
One of the very important key units of Spring Framework is the Aspect-oriented programming (AOP) framework. Aspect-Oriented Programming helps us to provide functionalities to break down program logic into distinct parts or modules is called AOP concerns. The functions that spread across multiple sections of an application are called cross-cutting concerns and these cross-cutting concerns functionalities must be separate from the application’s business logic. There are various good examples of aspects like logging, authentication, transaction management, auditing, spring-security, caching, etc.
The key concept of modularity is Object-Oriented Programming is the class, whereas in AOP the unit of modularity is the aspect. Spring dependency Injection usually helps us to lose coupling our application objects from each other and AOP helps us to decouple cross-cutting concerns from the objects that they affect.
Spring AOP provides interceptors to intercept an application. For example, when a method is executed, We can add extra functionality before or after the method execution.
Types of Advice
Spring AOP has five kinds of advice mentioned as Below −
SR.NO | ADVICE & DESCRIPTION |
---|---|
1 | before
This advice executes before a join point, but this advice does not have the ability to prevent execution flow to proceed to the join point (unless it throws an exception). |
2 | after
This advice is executed after a join point completes normally: for example if a method returns without throwing an exception. |
3 | after-returning
This advice runs after the method execution only if the method completes successfully. |
4 | after-throwing
This advice is executed if a method exiting by throwing an exception. |
5 | around
This is the most powerful kind of advice We can use around advice to perform custom behavior before and after the method invocation. This advice is also responsible to select whether to proceed to the joinpoint or to perform the advised method execution by returning its own return value or throwing an exception. |
In this demo project, We will learn about AfterReturning and AfterThrowing Advice:
pom.xml
We need to add spring and spring-aspects dependencies in Maven pom.xml file
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.kkhindigyan.org</groupId> <artifactId>AfterReturnAndAfterThrowingAdviceExample</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <org.springframework.version>5.2.13.RELEASE</org.springframework.version> <org.spring.aop.version>5.2.13.RELEASE</org.spring.aop.version> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${org.spring.aop.version}</version> </dependency> </dependencies> </project> |
Account.java
The model class which hold Account information data
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
package com.kkhindigyan.org.model; public class Account { private String accountNumber; private String accountDescription; public Account(String accountNumber, String accountDescription) { this.accountNumber = accountNumber; this.accountDescription = accountDescription; } public String getAccountNumber() { return accountNumber; } public String getAccountDescription() { return accountDescription; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((accountDescription == null) ? 0 : accountDescription.hashCode()); result = prime * result + ((accountNumber == null) ? 0 : accountNumber.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Account other = (Account) obj; if (accountDescription == null) { if (other.accountDescription != null) return false; } else if (!accountDescription.equals(other.accountDescription)) return false; if (accountNumber == null) { if (other.accountNumber != null) return false; } else if (!accountNumber.equals(other.accountNumber)) return false; return true; } @Override public String toString() { return "Account [accountNumber=" + accountNumber + ", accountDescription=" + accountDescription + "]"; } } |
AccountService.java
AccountService interface
1 2 3 4 5 6 7 8 9 |
package com.kkhindigyan.org.service; import com.kkhindigyan.org.model.Account; import com.kkhindigyan.org.service.exception.AccountNotFoundException; public interface AccountService { public abstract Account updateAccountBalance(Account account, Long amount) throws AccountNotFoundException; } |
AccountServiceImpl.java
AccountService interface implementation class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
package com.kkhindigyan.org.service.impl; import java.util.ArrayList; import java.util.List; import com.kkhindigyan.org.model.Account; import com.kkhindigyan.org.service.AccountService; import com.kkhindigyan.org.service.exception.AccountNotFoundException; public class AccountServiceImpl implements AccountService { private static List<Account> accountList = null; static { accountList = new ArrayList<Account>(); accountList.add(new Account("6770865432", "Money tranfer")); accountList.add(new Account("6770865400", "Money tranfer")); } @Override public Account updateAccountBalance(Account account,Long amount) throws AccountNotFoundException{ if(accountList.contains(account)) { System.out.println("Account No:"+account.getAccountNumber()+", Amount:"+amount); return account; }else { throw new AccountNotFoundException("Account Not Found!!"); } } } |
AccountNotFoundException.java
Custom Exception is designed to throw when Account details not found in the repository
1 2 3 4 5 6 7 8 9 |
package com.kkhindigyan.org.service.exception; public class AccountNotFoundException extends Exception { private static final long serialVersionUID = 1L; public AccountNotFoundException(String message) { super(message); } } |
AccountServiceAspect.java
This is the Simple java class where we have defined four methods beforeAdvice ,afterAdvice,afterReturnAdvice & afterTrhowingAdvice. These four methods we have configured as before, after ,after-returning and after-throwing advice in the applicationContext.xml spring config file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
package com.kkhindigyan.org.service.aop; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.aspectj.lang.JoinPoint; import com.kkhindigyan.org.model.Account; import com.kkhindigyan.org.service.exception.AccountNotFoundException; public class AccountServiceAspect { private static Log log = LogFactory.getLog(AccountServiceAspect.class.getName()); public void beforeAdvice(JoinPoint joinPoint) { Object[] args = joinPoint.getArgs(); for (Object object : args) { if( object instanceof Account) { System.out.println((Account)object); }else if(object instanceof Long) { System.out.println("Amount to be transferred ="+(Long)object); } } log.info("Before Method:"+joinPoint.getSignature()); } public void afterAdvice(JoinPoint joinPoint) { log.info("After Method:"+joinPoint.getSignature()); } public void afterReturnAdvice(Object account) { log.info("In afterReturnAdvice------------"); if( account instanceof Account) { System.out.println((Account)account); } } public void afterTrhowingAdvice(AccountNotFoundException ex) { log.error("There is an exception :"+ex.toString()); } } |
applicationContext.xml
To use the AOP namespace tags we need to import the spring AOP schema as shown in the below config file
An aspect is declared using the <aop:aspect> element within <aop:config> tag and the backing bean is referenced using the ref attribute in <aop:aspect>
Here “accountServiceAspect” is configured and dependency injected just like any other Spring bean.
A pointcut helps us to determine the join points (ie methods) of interest to be executed with different advice. Pointcut is defined here using <aop:pointcut> tag within <aop:config>
In this below config, we have defined a pointcut named ‘selectAll’ that will match the execution of updateAccountBalance(Account account,Long amount) method available in the AccountServiceImpl class under the package com.kkhindigyan.org.service.impl
We can usually declare any of the five advices inside an <aop:aspect> using the <aop:{Advice Name}> element
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/<span style="color: #ff6600;">aop</span> http://www.springframework.org/schema/aop/spring-aop.xsd"> <aop:config proxy-target-class="true"> <aop:pointcut expression="execution(* com.kkhindigyan.org.service.impl.AccountServiceImpl.*(..))" id="selectAll" /> <aop:aspect ref="accountServiceAspect"> <aop:after method="afterAdvice" pointcut-ref="selectAll" /> <aop:before method="beforeAdvice" pointcut-ref="selectAll" /> <aop:after-returning method="afterReturnAdvice" pointcut-ref="selectAll" returning="account"/> <aop:after-throwing method="afterTrhowingAdvice" pointcut-ref="selectAll" throwing="ex"/> </aop:aspect> </aop:config> <bean id="accountServiceAspect" class="com.kkhindigyan.org.service.aop.AccountServiceAspect"></bean> <bean id="accountService" class="com.kkhindigyan.org.service.impl.AccountServiceImpl"> </bean> </beans> |
ClientTest.java
This ClientTest class gets the AccountService bean from the applicationContext.xml file and calls the updateAccountBalance method of the EmployeeService after that before, after,after-returning and after-throwing advice called automatically.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
package com.kkhindigyan.org.client; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.kkhindigyan.org.model.Account; import com.kkhindigyan.org.service.AccountService; import com.kkhindigyan.org.service.impl.AccountServiceImpl; public class ClientTest { public static void main(String[] args) { AbstractApplicationContext ctx = null; try { ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); AccountService accountService = ctx.getBean("accountService", AccountServiceImpl.class); accountService.updateAccountBalance(new Account("6770865400", "Money tranfer"), 5000L); } catch (Exception e) { e.printStackTrace(); }finally { if(ctx != null) ctx.close(); } } } |
If you run ClientTest.java as Java Application then it will give the below output:
1 2 3 4 5 6 7 8 9 10 |
Account [accountNumber=6770865400, accountDescription=Money tranfer] Amount to be transferred =5000 Jun 19, 2021 11:03:32 AM com.kkhindigyan.org.service.aop.AccountServiceAspect beforeAdvice INFO: Before Method:Account com.kkhindigyan.org.service.impl.AccountServiceImpl.updateAccountBalance(Account,Long) Account No:6770865400, Amount:5000 Jun 19, 2021 11:03:32 AM com.kkhindigyan.org.service.aop.AccountServiceAspect afterAdvice INFO: After Method:Account com.kkhindigyan.org.service.impl.AccountServiceImpl.updateAccountBalance(Account,Long) Jun 19, 2021 11:03:32 AM com.kkhindigyan.org.service.aop.AccountServiceAspect afterReturnAdvice INFO: In afterReturnAdvice------------ Account [accountNumber=6770865400, accountDescription=Money tranfer] |
That’s all about Spring AOP AfterReturning and AfterThrowing Advice Example
You May Also Like:
Spring AOP Concepts and Terminology
Spring AOP Before and After Advice Example
Spring AOP Before and After Advice Using Annotations Example
Injecting Collections in Spring Framework Example
Spring Bean Definition Inheritance Example
Spring bean scopes with example
Spring JSR-250 Annotations with Example
Spring BeanPostProcessor Example
Spring JDBC Integration Example
Spring JDBC Annotation Example
Spring with Jdbc java based configuration example
Spring JDBC NamedParameterJdbcTemplate Example
How to call stored procedures in the Spring Framework?
Spring 5 and Hibernate 5 integration CRUD Example
Spring HibernateTempate Example
Spring and Hibernate Declarative Transaction Management Example
If you have any feedback or suggestion please feel free to drop in below comment box.