Spring AOP using Annotation

AOP a.k.a Aspect Oriented programming using Spring is a common usage now. In a nutshell it provides common functionality to be weaved into beans. Functionalities like logging before and after method is executed instead of being part of actual method implementation can be wired.

Some important notes about AOP with Spring:

  1. Spring AOP is implemented at Runtime and not compile time
  2. Spring only supports method level AOP so if you want to achieve AOP say when a constructor is called, look towards other implementation like AspectJ

Now there are few jargon about AOP which one should be familiar of, I will try to keep them one-liner

  1. Advice: Code which you want to run (common functionality)
  2. Join Point: Where all you want to run advice
  3. Point Cut: Of all the join point where exactly to run advice
  4. Aspect: What to apply and where to apply (Advice + Point Cut)

Enough of theory let’s make it clear by writing some code:

First let’s setup maven and define our dependencies (Need help creating Java Project using Maven in Eclipse ?)

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>TestSpring</groupId>
	<artifactId>TestSpring</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<repositories>
		<repository>
			<id>central</id>
			<name>release</name>
			<url>http://repo.springsource.org/release</url>
		</repository>
	</repositories>
	<build>
		<plugins>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>1.6</source>
					<target>1.6</target>
				</configuration>
			</plugin>
		</plugins>
	</build>
	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>3.1.2.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>3.1.2.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>3.1.2.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>cglib</groupId>
			<artifactId>cglib</artifactId>
			<version>2.2</version>
		</dependency>
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>1.6.11</version>
		</dependency>
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>1.6.11</version>
		</dependency>
	</dependencies>
</project>

Second let’s write our bean classes. Our use will have BookShelf with method to add and remove Book and Book will have few properties like name, author, publisher etc.

Book.java


package com.mumz.test.spring.aop;

/**
 * The Class Book.
 * 
 * @author prabhat.jha
 */
public class Book {

	/** The name. */
	private String name = null;

	/** The author. */
	private String author = null;

	/** The publisher. */
	private String publisher = null;

	/**
	 * The Constructor.
	 */
	public Book() {

	}

	/**
	 * Gets the name.
	 * 
	 * @return the name
	 */
	public String getName() {
		return name;
	}

	/**
	 * Sets the name.
	 * 
	 * @param name
	 *            the name
	 */
	public void setName(String name) {
		this.name = name;
	}

	/**
	 * Gets the author.
	 * 
	 * @return the author
	 */
	public String getAuthor() {
		return author;
	}

	/**
	 * Sets the author.
	 * 
	 * @param author
	 *            the author
	 */
	public void setAuthor(String author) {
		this.author = author;
	}

	/**
	 * Gets the publisher.
	 * 
	 * @return the publisher
	 */
	public String getPublisher() {
		return publisher;
	}

	/**
	 * Sets the publisher.
	 * 
	 * @param publisher
	 *            the publisher
	 */
	public void setPublisher(String publisher) {
		this.publisher = publisher;
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((author == null) ? 0 : author.hashCode());
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		result = prime * result
				+ ((publisher == null) ? 0 : publisher.hashCode());
		return result;
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (!(obj instanceof Book)) {
			return false;
		}
		Book other = (Book) obj;
		if (author == null) {
			if (other.author != null) {
				return false;
			}
		} else if (!author.equals(other.author)) {
			return false;
		}
		if (name == null) {
			if (other.name != null) {
				return false;
			}
		} else if (!name.equals(other.name)) {
			return false;
		}
		if (publisher == null) {
			if (other.publisher != null) {
				return false;
			}
		} else if (!publisher.equals(other.publisher)) {
			return false;
		}
		return true;
	}
}

Third our BookShelf.java.


package com.mumz.test.spring.aop;

import java.util.ArrayList;
import java.util.List;

/**
 * The Class BookShelf.
 * @author prabhat.jha
 */
public class BookShelf {
	
	/** The books. */
	private List<Book> books = null;
	
	/**
	 * The Constructor.
	 */
	public BookShelf(){
		this.books = new ArrayList<Book>();
	}
	
	/**
	 * Adds the book.
	 * 
	 * @param book
	 *            the book
	 * @return true, if adds the book
	 */
	public boolean addBook(Book book){
		return this.books.add(book);
	}
	
	/**
	 * Removes the book.
	 * 
	 * @param book
	 *            the book
	 * @return true, if removes the book
	 */
	public boolean removeBook(Book book){
		return this.books.remove(book);
	}
}

Both these classes are very simple and don’t have much functionality. Now we will use AOP and add log statement when ever addBook and removeBook methods are invoked.

Fourth we will implement our Advice (functionality which needs to be weaved).

BookAdvice

package com.mumz.test.spring.aop;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

/**
 * The Class BookAdvice.
 * @author prabhat.jha
 */
@Aspect
public class BookAdvice {
	
	/**
	 * Before add advice.
	 */
	@Before(value="execution(* com.mumz.test.spring.aop.BookShelf.addBook(..))")
	public void beforeAddAdvice(){
		System.out.println("Before adding new book in the list");
	}
	
	/**
	 * After add advice.
	 */
	@After("execution(* com.mumz.test.spring.aop.BookShelf.addBook(..))")
	public void afterAddAdvice(){
		System.out.println("After adding new book in the list");
	}
	
	/**
	 * Before remove advice.
	 */
	@Before("execution(* com.mumz.test.spring.aop.BookShelf.removeBook(..))")
	public void beforeRemoveAdvice(){
		System.out.println("Before adding new book in the list");
	}
	
	/**
	 * After remove advice.
	 */
	@After("execution(* com.mumz.test.spring.aop.BookShelf.removeBook(..))")
	public void afterRemoveAdvice(){
		System.out.println("After adding new book in the list");
	}
}

Important things to note in above code:

  1. @Aspect : This makes this class an aspect
  2. @Before : Pointcut (when it has to be invocked, so this says before method is executed)
  3. @After : Pointcut (when it has to be invocked, so this says after method is executed)
  4. execution(“* a.b.c(..)” : when method c of class b is executed which returns anything and takes variable arguments

Fifth our configuration file.

springconfiguration.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xmlns="http://www.springframework.org/schema/beans"
	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-3.1.xsd
		http://www.springframework.org/schema/context 
		http://www.springframework.org/schema/context/spring-context-3.1.xsd
		http://www.springframework.org/schema/aop 
		http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
	<bean id="bookShelf" class="com.mumz.test.spring.aop.BookShelf" scope="prototype"></bean>
	<bean id="book" class="com.mumz.test.spring.aop.Book" scope="prototype"></bean>
	<bean id="bookAdvice" class="com.mumz.test.spring.aop.BookAdvice"></bean>
	<aop:aspectj-autoproxy/>
</beans>

Final some test code to create and see AOP in action.

AopMainApp.java


package com.mumz.test.spring.aop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * The Class AopMainApp.
 * @author prabhat.jha
 */
public class AopMainApp {
	
	/**
	 * The main method.
	 * 
	 * @param args
	 *            the args
	 */
	public static void main(String[] args) {
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("springconfiguration.xml");
		BookShelf bookShelf = applicationContext.getBean(BookShelf.class);
		Book book  = applicationContext.getBean(Book.class);
		book.setAuthor("Test Author");
		book.setName("Test Book");
		book.setPublisher("Test Publisher");
		bookShelf.addBook(book);
		bookShelf.removeBook(book);
	}
}

That’s all, hope this is simple enough.

There is one comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s