In the previous Spring blog, you learned about Spring Framework and how to develop a simple application. But, to increase the modularity of Spring Applications, a new technique called AOP (Aspect-Oriented-Programming) was developed. In this Spring AOP Tutorial, you will learn about aspect-oriented programming and how to use it.
Below are the topics to be covered in Spring AOP Tutorial.
- Introduction to AOP
- Why AOP?
- Core AOP Concepts
- How to build an AOP Example?
- Types of Advices
- AspectJ Concepts
What Is Spring AOP? | Spring AOP (Aspect Oriented Programming) Tutorial
You may also go through this recording of Spring AOP Tutorial Concepts where you can understand the topics in a detailed manner with examples.
Introduction to AOP
Aspect Oriented Programming (AOP) compliments OOPs because it provides modularity. But, the key unit of modularity here is considered as an aspect rather than class. Here, AOP breaks the program logic into distinct parts (called concerns). It is used to increase modularity by cross-cutting concerns.
I hope you understood the concepts of AOP and cross-cutting concerns. Now, let’s move further and see why we need AOP.
Why AOP?
The most important functionality is AOP provides the pluggable way to dynamically add the additional concern before, after or around the actual logic. Suppose there are 10 methods as shown in the figure:
First, let’s understand Scenario- Here, I have to maintain a log and send notification after calling methods that start from m. So what is the problem without AOP? Here, We can call methods (that maintains a log and sends notification) from the methods starting with a. In such a scenario, we need to write the code in all the 5 methods. But, in case if a client says in future, I don’t have to send a notification, you need to change all the methods. It leads to a maintenance problem. So with AOP, we have below solution.
The solution with AOP– With AOP, we don’t have to call methods from the method. We can simply define the additional concern like maintaining a log, sending notification etc. in the method of a class. Its entry is given in the XML file. Suppose in future, if a client says to remove the notifier functionality, we need to change only in the XML file. So, maintenance is easy in AOP.
That’s the whole concept of why we need Aspect Oriented Programming in Springs. Now let’s move further in this Spring AOP Tutorial blog and understand some core concepts of Aspect Oriented Programming.
Core AOP Concepts
Spring AOP consists of 7 core concepts which are depicted in the following diagram:
- Aspect: The aspect is nothing but a class that implements the JEE application concerns which cut through multiple classes, such as transaction management, security etc. Aspects can be a normal class configured through Spring XML configuration. It can also be regular classes annotated using @Aspect annotation.
- Joinpoint: The joinpoint is a candidate point in the program execution where an aspect can be plugged in. It could be a method that is being called, an exception being thrown, or even a field being modified.
- Advice: Advice are the specific actions taken for a particular joinpoint. Basically, they are the methods that get executed when a certain joinpoint meets a matching pointcut in the application.
- Pointcut: A Pointcut is an expression that is matched with join points to determine whether advice needs to be executed or not.
- Target Object: These are the objects on which advices are applied. In Spring AOP, a subclass is created at runtime where the target method is overridden and advices are included based on their configuration.
- Proxy: It is an object that is created after applying advice to the target object. In clients perspective, object, the target object, and the proxy object are same.
- Weaving: Weaving is the process of linking an aspect with other application types or objects to create an advised object.
Having understood this, let’s move further and see what are the steps required to create an AOP
Steps to create AOP Example
- As shown in the above figure, first, we need Maven Dependencies. In actual, you need to create a maven project and add all the dependencies. If you wish to learn how to configure Spring Framework you can refer to this Spring Framework Tutorial.
- To create a Maven Project, install Eclipse for JEE developers and follow these steps.
- Click on File -> New -> Other-> Maven Project -> Next-> Choose maven-archetype-quickstart-> Specify GroupID -> Artifact ID -> Package name and then click on finish.
- Once you create a Maven Project, next thing that you have to do is to add maven dependencies in the pom.xml file.
- Your pom.xml file should consist of the below-mentioned dependencies for Aspect Oriented Programming.
<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.edureka</groupId> <artifactId>AOP</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging><name>AOP</name> <url>http://maven.apache.org</url><properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties><dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.3.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/aspectj/aspectjrt --> <dependency> <groupId>aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.5.4</version> </dependency> <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.2</version> </dependency> <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjtools --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjtools</artifactId> <version>1.9.2</version> </dependency> <!-- https://mvnrepository.com/artifact/org.ow2.asm/asm --> <dependency> <groupId>org.ow2.asm</groupId> <artifactId>asm</artifactId> <version>7.0</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.1.3.RELEASE</version> </dependency></dependencies> </project>
- After configuring your pom.xml file, all the required jar files for aspect-oriented programming will be imported. You can also copy and paste the required jar files dependency code from the maven repository. Take a look at the below image which depicts the imported jar files.
- Next, you can start writing a code for your project. For that, you must write Aspect and Pointcut expressions. After that, you can write the methods i.e. Joinpoints. And finally, you should write the main class and run the application.
Now let’s create a basic customer service class with a few print methods. In the below code I have used some setters and getters to display the results of name and URL.
package com.edureka.Edureka; public class CustomerService { private String name; private String url; public void setName(String name) { this.name = name; } public void setUrl(String url) { this.url = url; } public void printName() { System.out.println("Customer name : " + this.name); } public void printURL() { System.out.println("Customer website : " + this.url); } public void printThrowException() { throw new IllegalArgumentException(); } }
Here, next step is to write XML bean configuration file. In this, we will write a bean class with Bean id, class name, value etc. Let’s see how:
<?xmls version="1.0" encoding="UTF-8"?>; <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean id="customerService" class="com.edureka.Edureka.CustomerService">; <property name="name" value="Edureka" />; <property name="url" value="http://www.edureka.co" />; </bean>; </beans>;
Finally, we will write the main class to execute the program as shown in the below code
package com.edureka.Edureka; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.edureka.Edureka.CustomerService; public class App { public static void main(String[] args) { ApplicationContext appContext = new ClassPathXmlApplicationContext("Customer.xml"); CustomerService cust = (CustomerService) appContext.getBean("customerServiceProxy"); System.out.println("--------------------"); cust.printName(); System.out.println("--------------------"); cust.printURL(); System.out.println("--------------------"); try { cust.printThrowException(); } catch (Exception e) { } } }
This program on execution will display customer name and website in the console. So basically, this is how you can configure and write your AOP program. Now let’s delve deeper into Spring AOP Tutorial and understand different advice types.
Spring AOP Tutorial: Types of Advices
Several types of advices present in Spring AOP are as follows:
- Before: Here, advices execute before the joinpoint methods and are configured using @Before annotation mark.
- After returning: These advice types execute after the joinpoint methods complete the execution normally. They are configured using @AfterReturning annotation mark.
- After throwing: Here, advices execute only when the joinpoint method exits by throwing an exception. They are configured using @AfterThrowing annotation mark.
- After (finally): In this case, advices execute after a joinpoint method executes, regardless of the method’s exit (whether normal or exceptional return). They are configured using @After annotation mark.
- Around: These advice types execute before and after a join point and are configured using @Around annotation mark.
Now let’s see an example to understand how advices occur before and after the program execution. First, let’s see how it occurs before method execution. Let’s create a class that implements the MethodBeforeAdvice interface.
package com.edureka.Edureka; import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice; public class BeforeMethod implements MethodBeforeAdvice { @Override public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println("BeforeMethod : Before method executed!"); } }
Next, in the bean configuration file (Spring-Customer.xml), let’s create a bean for BeforeMethod class, and a new proxy object named ‘customerServiceProxy‘.
<?xmls version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean id="customerService" class="com.edureka.Edureka.CustomerService"> <property name="name" value="Edureka" /> <property name="url" value="http://www.edureka.co" /> </bean> <bean id="BeforeMethodBean" class="com.edureka.Edureka.BeforeMethod" /> <bean id="customerServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="customerService" /> <property name="interceptorNames"> <list> <value>beforeMethodBean</value> </list> </property> </bean> </beans>
Finally, let’s create a main class and execute the program.
package com.edureka.Edureka; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.edureka.Edureka.CustomerService; public class App { public static void main(String[] args) { ApplicationContext appContext = new ClassPathXmlApplicationContext("Customer.xml"); CustomerService cust = (CustomerService) appContext.getBean("customerServiceProxy"); System.out.println("--------------------"); cust.printName(); System.out.println("--------------------"); cust.printURL(); System.out.println("--------------------"); try { cust.printThrowException(); } catch (Exception e) { } } }
When you execute, it will execute the BeforeMethod’s before() method, before every customerService’s methods get executed.
Now, let’s see how after returning advice() occurs with the help of below example.
package com.edureka.Edureka; import java.lang.reflect.Method; import org.springframework.aop.AfterReturningAdvice; public class AfterMethod implements AfterReturningAdvice { @Override public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println("AfterMethod : After method Executed!"); } }
Now let’s configure bean xml configuration file
<?xmls version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean id="customerService" class="com.edureka.Edureka.CustomerService"> <property name="name" value="Edureka" /> <property name="url" value="http://www.edureka.co" /> </bean> <bean id="afterreturningMethodBean" class="com.edureka.Edureka.afterreturningMethod" /> <bean id="customerServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="target" ref="customerService" /> <property name="interceptorNames"> <list> <value>afterreturningMethodBean</value> </list> </property> </bean> </beans>
Finally, we will write the main class and execute the code.
package com.edureka.Edureka; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.edureka.Edureka.CustomerService; public class App { public static void main(String[] args) { ApplicationContext appContext = new ClassPathXmlApplicationContext(new String[] { "Spring-Customer.xml" }); CustomerService cust = (CustomerService) appContext.getBean("customerServiceProxy"); System.out.println("------------------------"); cust.printName(); System.out.println("------------------------"); cust.printURL(); System.out.println("------------------------"); try { cust.printThrowException(); } catch (Exception e) { } } }
Here, It will run the AfterMethod’s afterReturning() method, after every customerService’s methods that are returned result. So that’s all about the different types of advices. Now let’s jump into the last topic of Spring AOP Tutorial article and understand AspectJ Annotations.
AspectJ Concepts
The important aspect of Spring is the Aspect-Oriented Programming (AOP) framework. As we all know, the key unit of modularity in OOP(Object Oriented Programming) is the class, similarly, in AOP the unit of modularity is the aspect. Aspects enable the modularization of concerns such as transaction management that cut across multiple types and objects. To implement these concerns, AspectJ comes into the picture. AspectJ, a compatible extension to the Java programming language, is one implementation of AOP. It has grown into a complete and popular AOP framework. Since AspectJ annotations are supported by more and more AOP frameworks, AspectJ-style aspects are more likely to be reused in other AOP frameworks that support AspectJ.
Now, let’s jump into the last part of this Spring AOP Tutorial and write an example on Spring AspectJ Annotation. As you all know, advices need to be implemented, thus in order to specify the advices, point-cuts are necessary. So, before we write aspects, let’s understand what a point-cut is.
Pointcut
The pointcut is an expression language of Spring AOP. @Pointcut annotation defines the pointcut. Here, we can refer the pointcut expression by its name also. Let’s see a simple example.
@Pointcut("execution(*Operation.*(..))") private void dotask() {}
As you can see here, a name of the pointcut expression is dotask(). It will be applied on all the methods of Operation class regardless of the return type.
Now let’s see how Annotations can be applied and executed before the method execution.
The AspectJ Before Advice is applied before the actual business logic method. You can perform any operation here such as conversion, authentication etc.
Now, let’s create a class that contains actual business logic.
File: Operation.java
package com.edureka;
public class Operation{
public void msg(){System.out.println("msg method invoked");}
public int a(){System.out.println("a method invoked");return 2;}
public int b(){System.out.println("b method invoked");return3;}
}
Now, create the aspect class that contains before advice.
File: TrackOp.java
package com.edureka; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; @Aspect public class TrackOp{ @Pointcut(“execution(* Operation.*(..))") public void k(){} @Before(“k()”)//applying pointcut on before advice public void myadvice(JoinPoint jp){ System.out.println(“additional concern”); } }
Now create the applicationContext.xml file that defines beans.
File: applicationContext.xml
<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http:<span class="comment">//www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http:<span class="comment">//www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="opBean"class="com.edureka.Operation"></bean> <bean id="trackMyBean" class"com.edureka.TrackOp"></bean> <bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"> </beans>
Now, let’s call the actual method.
File: Test.java
package com.edureka; import org.springframework.context.ApplicationContext; import</span> org.springframework.context.support.ClassPathXmlApplicationContext; public class Test{ public static void main(String[] args){ ApplicationContext context= new ClassPathXmlApplicationContext"applicationContext.xml"); Operation e=(Operation)context.getBean("opBean"); System.out.println("calling msg..."); e.msg(); System.out.println("calling a..."): e.a(); System.out.println(calling b..."); e.b(); } }
Output
calling msg... additional concern msg()method invoked calling a... additional concern a() method invoked calling b... additional concern b() method invoked
As you can see, additional concern is printed before msg(), a() and b() method is invoked.
Now if you change the pointcut expression as given below:
@Pointcut("execution(*Operation.a*(..))")
Now additional concern will be applied for the methods starting with ‘a‘ in Operation class. The output will be as this:
calling msg... additional concern msg() method invoked calling a... additional concern a()method invoked calling b.. b() method invoked
Now you can see additional concern is not printed before b() method is invoked. Same goes with other types of advices as well. This is how you need to configure your code for aspectJ Annotation.
This brings us to the end of the blog on Spring AOP Tutorial. I tried my best to keep the concepts short and clear. Hope it helped you in understanding Spring AOP and its various features.
Now that you are done with Spring AOP Tutorial, check out the Spring Course by Edureka, a trusted online learning company with a network of more than 250,000 satisfied learners spread across the globe.
Got a question for us? Please mention it in the comments section of Spring AOP Tutorial blog and we will get back to you.