AOP

Spring AOP Example

In this example, we shall understand what is Aspect Oriented Programming and how Spring provides support to implement AOP.

1. Introduction to AOP

When designing a module, the focus is usually to maintain high cohesion in the module. Cohesion as per Wikipedia is the degree to which elements of a module belong together. But there are certain cross-cutting concerns like logging, transaction management, authorization etc which are required in almost to all modules. However, they do not serve any business purpose and thus reduce the focus of the module.

Aspect Oriented Programming provides a way to address this cross-cutting without embedding code specific to those tasks in the target module. AOP works by wrapping its code around the target module methods at run-time. Let’s set up the environment and see how Spring can help us in implementing Aspect Oriented Programming.

2. Project Setup

Create a simple Maven Project in Eclipse IDE by selecting the Skip Archetype Selection checkbox from the New Maven Project Pop-up.

Fig 1 : Create Maven Project
Fig 1 : Create Maven Project

We are using the below pom.xml to manage the dependencies for Spring AOP and AspectJ:

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.jcg.examples.springAoopExample</groupId>
	<artifactId>SpringAOPExample</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<dependencies>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>4.2.3.RELEASE</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>4.2.3.RELEASE</version>
		</dependency>

		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>1.8.8</version>
		</dependency>


		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>4.2.4.RELEASE</version>
		</dependency>


	</dependencies>

</project>

We shall be using AspectJ styled annotation for defining our point-cuts.

Eclipse will download the required JAR files and add the dependencies in the project classpath. Now that the setup is complete, let’s start with the implementation.

3. Implementation

We are given a business class around which we have to apply Aspect Oriented Programming. Let’s have a look at the business class:

BusinessTargetObject.java

package com.jcg.examples.bo;

import org.springframework.stereotype.Component;

@Component
public class BusinessTargetObject
{
		public String performTransaction(String arg)
		{
				System.out.println("Performing Txn for: " +arg);
				return "Transaction "+arg+" Successful";
		}
		
		public void merryGoAround()
		{
				System.out.println("Running merryGoAround for Business");
		}
		
		public void sayHello()
		{
				System.out.println("Hello says Hello..");
		}
		
		public void throwException()
		{
				System.out.println("Business class about throw an NPE..");
				throw new NullPointerException("THrowing custom Exception");
		}
}

The above class has two methods around which we need to add loggers. The class is annotated with @Component so that we can have its instance from the Spring container for testing.

Here’s the configuration xml which will configure the Spring Container :

Spring-configuration.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"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:jee="http://www.springframework.org/schema/jee" xmlns:lang="http://www.springframework.org/schema/lang"
	xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:util="http://www.springframework.org/schema/util"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
        http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

	<aop:aspectj-autoproxy />
	
	<context:component-scan base-package="com.jcg.examples"/>

</beans>

Line 16 tells the container that we are AspectJ controls for configuration. Spring uses Proxy pattern to create advice around a target object. Now, what is advice?

  • Advice : The actual code to be executed around the target for logging, authorization etc.
  • Target : The target around which the cross-cutting concern is to be fitted.In our case, it will be the methods in the BusinessTargetObject
  • Join Point : The point in the flow of the target program where the advice needs to be hooked to the target object.
  • Point-cut : We can think of point-cut as a sort of regular expression which selects a set of Join Points from the target, where the advice needs to run. As we are using AspectJ as our code weaver we are the ApectJ expression language as well.

We configure the point-cut in the Profiler.java file below:

Profiler.java

package com.jcg.examples.profiler;

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.springframework.stereotype.Component;

@Aspect
@Component
public class Profiler
{
		
		@Before("execution(* com.jcg.examples.bo.BusinessTargetObject.sayHello(..))")
		public void logBeforeTxn(JoinPoint joinpoint)
		{
				System.out.println("Beginning execution for "+joinpoint.getSignature().getName());
		}
		
		@After("execution(* com.jcg.examples.bo.BusinessTargetObject.sayHello(..))")
		public void logAfterTxn(JoinPoint joinpoint)
		{
				System.out.println("Execution completed for "+joinpoint.getSignature().getName());
		}
		
		@Around("execution(* com.jcg.examples.bo.BusinessTargetObject.merryGoAround(..))")
		public void logAroundTxn(ProceedingJoinPoint proceedingJoinPoint) throws Throwable
		{
				System.out.println("Beginning execution for "+proceedingJoinPoint.getSignature().getName());
				proceedingJoinPoint.proceed();
				System.out.println("Execution completed for "+proceedingJoinPoint.getSignature().getName());
		}
		
		@AfterReturning(pointcut = "execution(* com.jcg.examples.bo.BusinessTargetObject.performTransaction(..))",returning = "retVal")
		public void logResultsAfterTxn(JoinPoint joinpoint, Object retVal)
		{
				System.out.println("Execution completed for "+joinpoint.getSignature().getName());
				System.out.println("Value being returned is "+retVal);
		}
		
		@AfterThrowing(pointcut = "execution(* com.jcg.examples.bo.BusinessTargetObject.throwException(..))",throwing = "exception")
		public void logResultsAfterError(JoinPoint joinpoint, Throwable exception)
		{
				System.out.println("Execution completed for "+joinpoint.getSignature().getName());
				System.out.println("Error in Join Point due to : "+exception.getMessage());
				System.out.println("Advice complete");
		}
}

The first thing is the @Aspect annotation. This annotation is used to mark the class as an Aspect. The Spring Container cannot detect the class just by Aspect annotation, so we have marked it as Component for it to be auto-detected.

Next, we have a @Before annotation which marks the method to run the code before the execution of the target method begins. We pass the AspectJ point-cut expression as the parameter to the annotation. The advice will run for the methods for which the criteria defined by this point-cut expression is met. The AspectJ expression syntax can be understood in detail from the official page of the AspectJ.

Similarly, @After runs after the target method has completed running. One major difference between @After and @AfterReturning is that the latter also has the value returned by the target method. To access this value the developer has to pass the name of the argument in the annotation.

@Around This tag combines the functionalities of the @Before and @After annotations.

@AfterThrowing is executed if a join point throws an exception. The annotation allows the developer to access the exception object via its throwing attribute.

If a method satisfies more than one point cut expressions, the advice with the highest precedence will run first when starting with the execution of the Join point. After the execution of Join point is complete, the advice with the lowest precedence will run first.

We can set the order of the advises either by implementing the Ordered interface or by using the @Order annotation. for e.g.:

@Order(value=1)
		@After("execution(* com.jcg.examples.bo.BusinessTargetObject.sayHello(..))")
		public void logAfterTxn(JoinPoint joinpoint)
		{
			System.out.println("Execution completed for "+joinpoint.getSignature().getName());
		}

The advice with the lowest order value has the highest precedence.

Now, we are done with the implementation. Let’s test our code.

TestLoggingAspect.java

package com.jcg.examples.test;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;

import com.jcg.examples.bo.BusinessTargetObject;

public class TestLoggingAspect
{
		public static void main(String[] args)
		{
				ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new ClassPathResource("spring-configuration.xml").getPath());
				BusinessTargetObject target = context.getBean(BusinessTargetObject.class);
				target.sayHello();
				target.performTransaction("JavaCodeGeeks");
				target.merryGoAround();
				target.throwException();
				context.close();
		}
}

In the above class, we have retrieved the instance of BusinessTargetObject and executed its method. The advices from the Profiler class run as and when their pointcut expressions are satisfied

Here’s how the output looks like:

Beginning execution for sayHello
Hello says Hello..
Execution completed for sayHello
Performing Txn for: JavaCodeGeeks
Execution completed for performTransaction
Value being returned is Transaction JavaCodeGeeks Successful
Beginning execution for merryGoAround
Running merryGoAround for Business
Execution completed for merryGoAround
Business class about throw an NPE..
Execution completed for throwException
Error in Join Point due to : THrowing custom Exception
Advice complete

4. Download the Source Code

Here we understood what Aspect Oriented Programming is and how we can use it to improve cohesion in our modules using Spring.

Download
You can download the source code of this example here: SpringAOPExample.zip

Chandan Singh

Chandan holds a degree in Computer Engineering and is a passionate software programmer. He has good experience in Java/J2EE Web-Application development for Banking and E-Commerce Domains.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button