Overview of Spring Aspect Oriented Programming (AOP)
This in-depth view of Aspect Oriented Programming in Spring includes extended examples, use cases, and definitions of AOP terms.
Join the DZone community and get the full member experience.
Join For FreeIn this blog post, Java web development professionals give a descriptive view about Spring Aspect Oriented Programming (AOP) for general readers. You will read about advantages, disadvantages, uses, and important terminologies with examples.
Advantages of Spring AOP
- AOP is non-invasive:
- Service or Domain classes get advice by the aspects (cross-cutting concerns) without adding Spring AOP related classes or interfaces into the service or domain classes.
- Allows the developers to concentrate on the business logic, instead of the cross-cutting concerns.
2. AOP is implemented in pure Java:
- There is no need for a special compilation unit or special class loader
3. It uses Spring’s IOC container for dependency injection:
- Aspects can be configured as normal spring beans.
4. Like any other AOP framework, it weaves cross-cutting concerns into the classes, without making a call to the cross-cutting concerns from those classes.
5. Centralizes or modularizes the cross-cutting concerns:
- Easy to maintain and make changes to the aspects.
- Changes only need to be made in one place.
6. Provision to create aspects using schema-based (XML configuration) or @AspectJ annotation based style.
7. Easy to configure.
Disadvantages of Spring AOP
1. A small difficulty is debugging the AOP framework-based application code.
- Since the business classes are advised after the scene with aspects.
2. Since it uses proxy-based AOP, only method-level advising is supported; it does not support field-level interception
- So join-points can be at method level not at field level in a class.
3. Only methods with public visibility will be advised:
- Methods with private, protected, or default visibility will not be advised.
4. There's small runtime overhead, but its negotiable:
- The overhead is in nano-seconds.
5. Aspects cannot advise other Aspects - it's not possible to have aspects as targets of advice from other aspects.
- Because once you mark one class as an aspect (either use XML or annotation), Spring excludes it from being auto-proxied.
6. Local or internal method calls within an advised class don’t get intercepted by proxy, so the advice method of the aspect does not get fired or invoked.
7. It is not for advising fine-grained objects (or domain objects)—it is best suitable for coarse-grained objects due to performance.
Uses of Spring AOP
- AOP is commonly used as an implementation of "cross-cutting concerns," which means it defines, in one place, functionality that is needed in multiple places throughout a code.
- A cross-cutting concern that can affect the whole application should be centralized in one place in code as much as possible, such as authentication, logging, transaction management, security, etc.
Spring AOP
- Aspect Oriented Programming (AOP) supplements Object Oriented Programming (OOP) by providing another way of thinking about program structure.
- The key unit of modularity in OOPs is the class—in AOP the unit of modularity is the aspect.
- Aspects help to modularize cross-cutting concerns, which means cross-cutting concerns can be described by any functionality that affects multiple types and objects.
- One key component of Spring is the Aspect Oriented Programming (AOP) framework.
- While Spring IoC container doesn't depend on the AOP framework, this means you don't need to use AOP if you do not want to—AOP supplements Spring IoC to provide a capable middleware solution.
Spring AOP can work with five kinds of advice, mentioned below:
Types of Advice
- Before: This advice runs before the execution of Join point methods. This functionality occurs before the advised method is invoked.
- After: This advice gets executed after the Join point method finishes executing. This functionality occurs after the advice method completes, regardless of outcome.
- After-returning: This advice method executes only if the Join point method executes normally. This functionality occurs after the advice method successfully completes.
- After-throwing: This advice gets executed only when the join point method throws an exception., We can use this to roll back the transaction declaratively.
- Around: Wraps the advised method, providing functionality before and after the advised method is invoked.
AOP Terminologies
- Join Points: A Join Point is a point in the execution of the application where an aspect can be plugged in. This point could be a method being called, an exception being thrown, or even a field being modified.
- Pointcuts: Pointcuts are expressions that are matched with Join points to determine whether advice needs to be executed or not. This is a set of more than one Join point where an advice should be executed.
- Advice: Advice defines both the when and where of an aspect. The actual action to be taken before or after method execution. Actual piece of code that is invoked during program execution by Spring's Aspect Oriented Programming framework.
- Aspects: An aspect is the merger of Advice and Pointcuts. Advice and pointcuts define everything known about an aspect, what it does and where and when it does it.
- Introductions: An Introduction allows adding new methods or attributes to existing classes. The new method and instance variable can be introduced to existing classes without having to change them, giving them new state and behavior.
- Weaving: Weaving is the process of applying aspects to a target object to create a new proxied object. The target object at the specified Join points.
The weaving can occur at several points in the target object’s lifetime:
- Compile Time: Aspects are woven in as the target class is compiled. It requires a special compiler. AspectJ’s weaving compiler weaves aspects this way.
- Classload Time: Aspects are woven in as the target class is loaded into the JVM. It requires a special ClassLoader that enhances that target class's bytecode before the class is introduced into the application. AspectJ 5’s load-time weaving (LTW) support weaves aspects this way.
- Runtime: Aspects are woven in sometime during the execution of the application. An AOP container will dynamically generate a proxy object that will delegate to the target object while weaving in the aspects.
AOP Proxies
- Spring AOP is proxy-based. It is vitally important that you grasp the semantics of what that last statement actually means before your write own aspects or use any of the Spring AOP-based aspects supplied with the Spring Framework.
- Consider first the scenario where you have a un-proxied, straight object reference—nothing special about it, plain vanilla, as illustrated by the following code:
public class SamplePojo implements Pojo
{
public void foo() {
this.bar();
}
public void bar() {
// some logic...
}
}
- A method on an object reference, the method is invoked directly on the object reference.
public class MainClass
{
public static void main(String[] args)
{
Pojo pojo = new SamplePojo();
pojo.foo();
}
}
Things change slightly when the reference to that client code is a proxy.
public class MainClass
{
public static void main(String[] args)
{
ProxyFactory factory = new ProxyFactory(new SamplePojo());
factory.addInterface(Pojo.class);
factory.addAdvice(new RetryAdvice());
Pojo pojo = (Pojo) factory.getProxy();
pojo.foo();
}
}
- The key thing to understand here is that the client code inside the main (...) method of the MainClass class has a reference to the proxy. This means method calls on that object reference will be calls on the proxy, and as such the proxy will be able to delegate to all the interceptors (advice) that are relevant to the particular method call.
- Once the call has finally reached the target object reference, the SamplePojo object reference in this case, any method calls that it may make on itself, such as this.bar() or this.foo(), are to be invoked against this reference, and not that proxy. This has important implications.
Spring AOP Example
- pom.xml
<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.aop.example.enterprise</groupId>
<artifactId>springexample</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
<properties>
<spring.version>3.2.3.RELEASE</spring.version>
</properties>
</project>
2. Create an advice
In AOP the advice is an action taken before or after method execution. There are different types of advice such as before, after, around, after-returning and after-throwing advice. Below all types advice and create an example of each them.
SampleService.java
package com.aop.example.enterprise;
public class SampleService {
private String name;
private int id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public void printDetails() {
System.out.println("SampleService : Method printDetails() : My name is " + name + " and my id is " + id);
}
public void checkName() {
if (name.length() < 15) {
throw new IllegalArgumentException();
}
}
public void sayHello(String message){
System.out.println("SampleService : Method sayHello() : Hello.. " + message);
}
}
2.1 Before Advice
This advice runs before the execution of Join point methods, but doesn't have to prevent execution flow proceeding to method execution.
BeforeMethod.java
package com.javacodegeeks.snippets.enterprise.aop;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class BeforeMethod implements MethodBeforeAdvice
{
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("===SPRING AOP=== BeforeMethod : Execute before method!");
}
}
The advice must be defined in Spring configuration file. A proxy object must be created of ProxyFactoryBean type. It has an interceptorNames property. The property value is a list of bean names.
applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd">
<bean id="sampleServiceBean" class="com.aop.example.enterprise.SampleService">
<property name="name" value="How are you ?" />
<property name="id" value="456123" />
</bean>
<bean id="beforeMethodBean"
class="com.aop.example.enterprise.aop.BeforeMethod" />
<bean id="sampleServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="sampleServiceBean" />
<property name="interceptorNames">
<list>
<value>beforeMethodBean</value>
</list>
</property>
</bean>
</beans>
Load the sampleServiceProxy bean in Application.class in order to run the application.
Application.java
package com.aop.example.enterprise;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
SampleService sampleService = (SampleService) context.getBean("sampleServiceProxy");
sampleService.printDetails();
try{
sampleService.checkName();
} catch(Exception e){
System.out.println("SampleService: Method checkName() thrown exception");
}
sampleService.sayHello("JavaTutorials");
context.close();
}
}
Output:
===SPRING AOP=== BeforeMethod : Execute before method!
SimpleService : Method printDetails() : My name is How are you ? and my id is 456123
===SPRING AOP=== BeforeMethod : Execute before method!
SimpleService: Method checkName() thrown exception
===SPRING AOP=== BeforeMethod : Execute before method!
SimpleService : Method sayHello() : Hello.. JavaTutorials
2.2 After Returning Advice
AfterReturningMethod.java
package com.aop.example.enterprise.aop;
import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
public class AfterReturningMethod implements AfterReturningAdvice {
public void afterReturning(Object returnValue, Method method,
Object[] args, Object target) throws Throwable {
System.out.println("===SPRING AOP=== AfterReturningMethod : Execute after return method ");
}
}
Add a new bean, applicationContext.xml.
applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd">
<bean id="sampleServiceBean" class="com.aop.example.enterprise.SampleService">
<property name="name" value="How are you ?" />
<property name="id" value="456123" />
</bean>
<bean id="beforeMethodBean"
class="com.aop.example.enterprise.aop.BeforeMethod" />
<bean id="afterReturningMethodBean"
class="com.aop.example.enterprise.aop.AfterReturningMethod" />
<bean id="sampleServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="sampleServiceBean" />
<property name="interceptorNames">
<list>
<value>beforeMethodBean</value>
<value>afterReturningMethodBean</value>
</list>
</property>
</bean>
</beans>
Output:
===SPRING AOP=== BeforeMethod : Execute before method!
SimpleService : Method printDetails() : My name is How are you ? and my id is 456123
===SPRING AOP=== AfterReturningMethod : Execute after return method
===SPRING AOP=== BeforeMethod : Execute before method!
SimpleService: Method checkName() thrown exception
===SPRING AOP=== BeforeMethod : Execute before method!
SimpleService : Method sayHello() : Hello.. JavaTutorials
===SPRING AOP=== AfterReturningMethod : Execute after return method
2.3 AfterThrowingExceptionMethod.java
AfterThrowingExceptionMethod.java
package com.aop.example.enterprise.aop;
import org.springframework.aop.ThrowsAdvice;
public class AfterThrowingExceptionMethod implements ThrowsAdvice {
public void afterThrowing(IllegalArgumentException e) throws Throwable {
System.out.println("===SPRING AOP=== AfterThrowingExceptionMethod : Execute when method throws exception");
}
}
applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd">
<bean id="sampleServiceBean" class="com.aop.example.enterprise.SampleService">
<property name="name" value="How are you ?" />
<property name="id" value="456123" />
</bean>
<bean id="beforeMethodBean"
class="com.aop.example.enterprise.aop.BeforeMethod" />
<bean id="afterReturningMethodBean"
class="com.aop.example.enterprise.aop.AfterReturningMethod" />
<bean id="afterThrowingExceptionMethodBean"
class="com.aop.example.enterprise.aop.AfterThrowingExceptionMethod" />
<bean id="sampleServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="sampleServiceBean" />
<property name="interceptorNames">
<list>
<value>beforeMethodBean</value>
<value>afterReturningMethodBean</value>
<value>afterThrowingExceptionMethodBean</value>
</list>
</property>
</bean>
</beans>
Output:
===SPRING AOP=== BeforeMethod : Execute before method!
SimpleService : Method printDetails() : My name is How are you ? and my id is 456123
****SPRING AOP**** DoAfterReturningMethod : Executing after method return!
===SPRING AOP=== BeforeMethod : Execute before method!
===SPRING AOP=== AfterThrowingExceptionMethod : Execute when method throws exception
SimpleService: Method checkName() thrown exception
===SPRING AOP=== BeforeMethod : Execute before method!
SimpleService : Method sayHello() : Hello.. JavaTutorials
===SPRING AOP=== AfterReturningMethod : Execute after return method
2.4 Around Advice
AroundMethod.java
package com.aop.example.enterprise.aop;
import java.util.Arrays;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class AroundMethod implements MethodInterceptor {
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("===SPRING AOP=== AroundMethod: Method name : " + methodInvocation.getMethod().getName());
System.out.println("===SPRING AOP=== AroundMethod: Method arguments :” + Arrays.toString(methodInvocation.getArguments()));
System.out.println("===SPRING AOP=== AroundMethod: Before method execute");
try {
Object result = methodInvocation.proceed();
System.out.println("===SPRING AOP=== AroundMethod: After method execute");
return result;
} catch (IllegalArgumentException e) {
// same with ThrowsAdvice
System.out.println("===SPRING AOP=== AroundMethod: When method exception throws ");
throw e;
}
}
}
applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd">
<bean id="simpleServiceBean" class="com.aop.example.enterprise.SimpleService">
<property name="name" value="How are you?" />
<property name="id" value="456123" />
</bean>
<bean id="beforeMethodBean"
class="com.aop.example.enterprise.aop.BeforeMethod" />
<bean id="afterReturningMethodBean"
class="com.aop.example.enterprise.aop.AfterReturningMethod" />
<bean id="afterThrowingExceptionMethodBean"
class="com.aop.example.enterprise.aop.AfterThrowingExceptionMethod" />
<bean id="aroundMethodBean"
class="com.aop.example.enterprise.aop.AroundMethod" />
<bean id="sampleServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="sampleServiceBean" />
<property name="interceptorNames">
<list>
<value>beforeMethodBean</value>
<value>afterReturningMethodBean</value>
<value>afterThrowingExceptionMethodBean</value>
<value>aroundMethodBean</value>
</list>
</property>
</bean>
</beans>
Output:
===SPRING AOP=== BeforeMethod : Execute before method!
===SPRING AOP=== AroundMethod: Method name : printDetails
===SPRING AOP=== AroundMethod: Method arguments : []
===SPRING AOP=== AroundMethod: Before method execute
SimpleService : Method printDetails() : My name is Hello and my id is 12345
===SPRING AOP=== AroundMethod: After method execute
===SPRING AOP=== DoAfterReturningMethod : Executing after method return!
===SPRING AOP=== BeforeMethod : Execute before method!
===SPRING AOP=== AroundMethod: Method name : checkName
===SPRING AOP=== AroundMethod: Method arguments : []
===SPRING AOP=== AroundMethod: Before method execute
===SPRING AOP=== AroundMethod: When method exception throws
===SPRING AOP=== AfterThrowingExceptionMethod : Execute when method throws exception
SimpleService: Method checkName() thrown exception
===SPRING AOP=== BeforeMethod : Execute before method!
===SPRING AOP=== AroundMethod: Method name : sayHello
===SPRING AOP=== AroundMethod: Method arguments : [JavaTutorials]
===SPRING AOP=== AroundMethod: Before method execute
SimpleService : Method sayHello() : Hello.. JavaTutorials
===SPRING AOP=== AroundMethod: After method execute
===SPRING AOP=== AfterReturningMethod : Execute after return method
This is the overview of Spring Aspect Oriented Programming (AOP) by professionals. If you don’t understand any point in this post, Java web development experts are here to help you. Ask your questions and doubts and get a response in time.
Opinions expressed by DZone contributors are their own.
Comments