AOP

Spring AOP Example

With this tutorial we shall show you how to use Aspect Oriented Programming in Spring Framework. AOP is used in the Spring Framework to provide declarative enterprise services, especially as a replacement for EJB declarative services. It is also used to allow users to implement custom aspects, complementing their use of OOP with AOP.

We will demonstrate how to create and apply some central AOP concepts. In short we will create all types of advices, we will use a pointcut and an advisor over an advice and we will check on some special features of Spring in interceptors and proxy beans.

Our preferred development environment is Eclipse. We are using Eclipse Juno (4.2) version, along with Maven Integration plugin version 3.1.0. You can download Eclipse from here and Maven Plugin for Eclipse from here. The installation of Maven plugin for Eclipse is out of the scope of this tutorial and will not be discussed. We are also using Spring version 3.2.3 and the JDK 7_u_21.

Let’s begin.

1. Create a new Maven project

Go to File -> Project ->Maven -> Maven Project.

New-Maven-Project

In the “Select project name and location” page of the wizard, make sure that “Create a simple project (skip archetype selection)” option is checked, hit “Next” to continue with default values.

Maven-Project-Name-Location

In the “Enter an artifact id” page of the wizard, you can define the name and main package of your project. We will set the “Group Id” variable to "com.javacodegeeks.snippets.enterprise" and the “Artifact Id” variable to "springexample". The aforementioned selections compose the main project package as "com.javacodegeeks.snippets.enterprise.springexample" and the project name as "springexample". Hit “Finish” to exit the wizard and to create your project.

Configure-Maven-Project

The Maven project structure is shown below:

Maven-project-structure

    It consists of the following folders:

  • /src/main/java folder, that contains source files for the dynamic content of the application,
  • /src/test/java folder contains all source files for unit tests,
  • /src/main/resources folder contains configurations files,
  • /target folder contains the compiled and packaged deliverables,
  • the pom.xml is the project object model (POM) file. The single file that contains all project related configuration.

2. Add Spring 3.2.3 dependency

  • Locate the “Properties” section at the “Overview” page of the POM editor and perform the following changes:
    Create a new property with name org.springframework.version and value 3.2.3.RELEASE.
  • Navigate to the “Dependencies” page of the POM editor and create the following dependencies (you should fill the “GroupId”, “Artifact Id” and “Version” fields of the “Dependency Details” section at that page):
    Group Id : org.springframework Artifact Id : spring-web Version : ${org.springframework.version}

Alternatively, you can add the Spring dependencies in Maven’s pom.xml file, by directly editing it at the “Pom.xml” page of the POM editor, as shown below:
 
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.javacodegeeks.snippets.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>

As you can see Maven manages library dependencies declaratively. A local repository is created (by default under {user_home}/.m2 folder) and all required libraries are downloaded and placed there from public repositories. Furthermore intra – library dependencies are automatically resolved and manipulated.

3. Create an Advice

In AOP the Advice is an action taken before or after a method execution. There are different types of advice, such as “around,” “before” and “after” advice. Below we introduce all types of advice and create an example for each one of them.

SimpleService.java class is the class whose methods will be intercepted by the advices we will create.

SimpleService.java

package com.javacodegeeks.snippets.enterprise;

public class SimpleService {

	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 printNameId() {
		System.out.println("SimpleService : Method printNameId() : My name is " + name
			 + " and my id is " + id);
	}

	public void checkName() {
		if (name.length() < 20) {
			throw new IllegalArgumentException();
		}
	}

	public void sayHello(String message){
		System.out.println("SimpleService : Method sayHello() : Hello! " + message);
	}
}

3.1 Before Advice

Before Advice executes before a method execution, but does not have the ability to prevent execution flow proceeding to the method execution (unless it throws an exception). The class that implements it is the one below:

DoBeforeMethod.java

package com.javacodegeeks.snippets.enterprise.aop;

import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
 
public class DoBeforeMethod implements MethodBeforeAdvice
{
	public void before(Method method, Object[] args, Object target)
		throws Throwable {
	        System.out.println("****SPRING AOP**** DoBeforeMethod : Executing before method!");
	}
}

The advice bean must be defined in Spring configuration file. In addition, a proxy object must be created, of ProxyFactoryBean type. The proxy bean has a target property. Its value is a reference to the bean whose methods will be intercepted. It also has an interceptorNames property. The property value is a list of bean names that represent the advices that will be applied on this proxy /target object.

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.javacodegeeks.snippets.enterprise.SimpleService">
		<property name="name" value="Hello" />
		<property name="id" value="12345" />
	</bean>

	<bean id="doBeforeMethodBean"
		class="com.javacodegeeks.snippets.enterprise.aop.DoBeforeMethod" />

	<bean id="simpleServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
		<property name="target" ref="simpleServiceBean" />
		<property name="interceptorNames">
			<list>
				<value>doBeforeMethodBean</value>
			</list>
		</property>
	</bean>
</beans>

We must load the simpleServiceProxy bean in App.class in order to run the application, as shown below:

App.java

package com.javacodegeeks.snippets.enterprise;

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

public class App {

	public static void main(String[] args) {
	
			ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
			SimpleService simpleService = (SimpleService) context.getBean("simpleServiceProxy");
			simpleService.printNameId();
			System.out.println("--------------");
			try{
				simpleService.checkName();
			} catch(Exception e){
				System.out.println("SimpleService: Method checkName() exception thrown..");
			}
			System.out.println("--------------");
			simpleService.sayHello("Javacodegeeks");
			context.close();
	}
}

As a result, the before(Method method, Object[] args, Object target) method of the DoBeforeMethod Advice is invoked before the simpleService‘s methods execution.

Output

****SPRING AOP**** DoBeforeMethod : Executing before method!
SimpleService : Method printNameId() : My name is Hello and my id is 12345 
--------------
****SPRING AOP**** DoBeforeMethod : Executing before method!
SimpleService: Method checkName() exception thrown..
--------------
****SPRING AOP**** DoBeforeMethod : Executing before method!
SimpleService : Method sayHello() : Hello! Javacodegeeks

3.2 After Returning Advice

After returning advice is the Advice to be executed after a method execution completes normally: for example, if a method returns without throwing an exception. The class that implements it is the one below:

DoAfterReturningMethod.java

package com.javacodegeeks.snippets.enterprise.aop;

import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;

public class DoAfterReturningMethod implements AfterReturningAdvice {
	public void afterReturning(Object returnValue, Method method,
			Object[] args, Object target) throws Throwable {
		System.out.println("****SPRING AOP**** DoAfterReturningMethod : Executing after method return!");
	}

}

We add the new bean in applicationContext.xml, following the same steps as above.

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.javacodegeeks.snippets.enterprise.SimpleService">
		<property name="name" value="Hello" />
		<property name="id" value="12345" />
	</bean>

	<bean id="doBeforeMethodBean"
		class="com.javacodegeeks.snippets.enterprise.aop.DoBeforeMethod" />

	<bean id="doAfterReturningMethodBean"
		class="com.javacodegeeks.snippets.enterprise.aop.DoAfterReturningMethod" />

	<bean id="simpleServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
		<property name="target" ref="simpleServiceBean" />
		<property name="interceptorNames">
			<list>
				<value>doBeforeMethodBean</value>
				<value>doAfterReturningMethodBean</value>
			</list>
		</property>
	</bean>
</beans>

Now, after running App.java class again we can see that the afterReturning(Object returnValue, Method method, Object[] args, Object target) method of DoAfterReturningMethod advice is executed after the simpleService‘s methods’ execution. Note that since checkName() method throws an exception and does not return normally, it is not being intercepted by DoAfterReturningMethod.

Output

****SPRING AOP**** DoBeforeMethod : Executing before method!
SimpleService : Method printNameId() : My name is Hello and my id is 12345
****SPRING AOP**** DoAfterReturningMethod : Executing after method return!
--------------
****SPRING AOP**** DoBeforeMethod : Executing before method!
SimpleService: Method checkName() exception thrown..
--------------
****SPRING AOP**** DoBeforeMethod : Executing before method!
SimpleService : Method sayHello() : Hello! Javacodegeeks
****SPRING AOP**** DoAfterReturningMethod : Executing after method return!

3.3 After Throwing Advice

After throwing Advice is the Advice to be executed if a method exits by throwing an exception. The class that implements it in the example is the one shown below:

DoAfterThrowingExceptionMethod.java

package com.javacodegeeks.snippets.enterprise.aop;

import org.springframework.aop.ThrowsAdvice;

public class DoAfterThrowingExceptionMethod implements ThrowsAdvice {
	public void afterThrowing(IllegalArgumentException e) throws Throwable {
		System.out.println("****SPRING AOP**** DoAfterThrowingExceptionMethod : Executing when method throws exception!");
	}
}

We add the new bean in 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="simpleServiceBean" class="com.javacodegeeks.snippets.enterprise.SimpleService">
		<property name="name" value="Hello" />
		<property name="id" value="12345" />
	</bean>

	<bean id="doBeforeMethodBean"
		class="com.javacodegeeks.snippets.enterprise.aop.DoBeforeMethod" />

	<bean id="doAfterReturningMethodBean"
		class="com.javacodegeeks.snippets.enterprise.aop.DoAfterReturningMethod" />

<bean id="doAfterThrowingExceptionMethodBean"
		class="com.javacodegeeks.snippets.enterprise.aop.DoAfterThrowingExceptionMethod" />

	<bean id="simpleServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
		<property name="target" ref="simpleServiceBean" />
		<property name="interceptorNames">
			<list>
				<value>doBeforeMethodBean</value>
				<value>doAfterReturningMethodBean</value>
				<value>doAfterThrowingExceptionMethodBean</value>
			</list>
		</property>
	</bean>
</beans>

Now, after running the example again we can see that only the checkName() method is being intercepted by the DoAfterThrowingExceptionMethod.

Output

****SPRING AOP**** DoBeforeMethod : Executing before method!
SimpleService : Method printNameId() : My name is Hello and my id is 12345
****SPRING AOP**** DoAfterReturningMethod : Executing after method return!
--------------
****SPRING AOP**** DoBeforeMethod : Executing before method!
****SPRING AOP**** DoAfterThrowingExceptionMethod : Executing when method throws exception!
SimpleService: Method checkName() exception thrown..
--------------
****SPRING AOP**** DoBeforeMethod : Executing before method!
SimpleService : Method sayHello() : Hello! Javacodegeeks
****SPRING AOP**** DoAfterReturningMethod : Executing after method return!

3.4 Around Advice

Around advice is the Advice that surrounds a join point such as a method invocation. This is the most powerful kind of advice. Around advice can perform custom behavior before and after the method invocation. It is also responsible for choosing whether to proceed to the join point or to shortcut the advised method execution by returning its own return value or throwing an exception. The class that implements an around Advice is shown below:

DoAroundMethod.java

package com.javacodegeeks.snippets.enterprise.aop;

	import java.util.Arrays;
	 
	import org.aopalliance.intercept.MethodInterceptor;
	import org.aopalliance.intercept.MethodInvocation;

public class DoAroundMethod implements MethodInterceptor {
		public Object invoke(MethodInvocation methodInvocation) throws Throwable {
	 
			System.out.println("****SPRING AOP**** DoAroundMethod: Method name : "
					+ methodInvocation.getMethod().getName());
			System.out.println("****SPRING AOP**** DoAroundMethod: Method arguments : "
					+ Arrays.toString(methodInvocation.getArguments()));
			// same with MethodBeforeAdvice
			System.out.println("****SPRING AOP**** DoAroundMethod: Before method executing!");
	 
			try {
				// proceed to original method call
				Object result = methodInvocation.proceed();
				// same with AfterReturningAdvice
				System.out.println("****SPRING AOP**** DoAroundMethod: After method executing!");
				return result;
	 
			} catch (IllegalArgumentException e) {
				// same with ThrowsAdvice
				System.out.println("****SPRING AOP**** DoAroundMethod: When method throws Exception!");
				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.javacodegeeks.snippets.enterprise.SimpleService">
		<property name="name" value="Hello" />
		<property name="id" value="12345" />
	</bean>

	<bean id="doBeforeMethodBean"
		class="com.javacodegeeks.snippets.enterprise.aop.DoBeforeMethod" />

	<bean id="doAfterReturningMethodBean"
		class="com.javacodegeeks.snippets.enterprise.aop.DoAfterReturningMethod" />

<bean id="doAfterThrowingExceptionMethodBean"
		class="com.javacodegeeks.snippets.enterprise.aop.DoAfterThrowingExceptionMethod" />

<bean id="doAroundMethodBean"
		class="com.javacodegeeks.snippets.enterprise.aop.DoAroundMethod" />

	<bean id="simpleServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
		<property name="target" ref="simpleServiceBean" />
		<property name="interceptorNames">
			<list>
				<value>doBeforeMethodBean</value>
				<value>doAfterReturningMethodBean</value>
				<value>doAfterThrowingExceptionMethodBean</value>
				<value>doAroundMethodBean</value>
			</list>
		</property>
	</bean>
</beans>

When running the application with the DoAroundMethod advice we can see that it intercepts all methods of simpleService.

Output

****SPRING AOP**** DoBeforeMethod : Executing before method!
****SPRING AOP**** DoAroundMethod: Method name : printNameId
****SPRING AOP**** DoAroundMethod: Method arguments : []
****SPRING AOP**** DoAroundMethod: Before method executing!
SimpleService : Method printNameId() : My name is Hello and my id is 12345
****SPRING AOP**** DoAroundMethod: After method executing!
****SPRING AOP**** DoAfterReturningMethod : Executing after method return!
--------------
****SPRING AOP**** DoBeforeMethod : Executing before method!
****SPRING AOP**** DoAroundMethod: Method name : checkName
****SPRING AOP**** DoAroundMethod: Method arguments : []
****SPRING AOP**** DoAroundMethod: Before method executing!
****SPRING AOP**** DoAroundMethod: When method throws Exception!
****SPRING AOP**** DoAfterThrowingExceptionMethod : Executing when method throws exception!
SimpleService: Method checkName() exception thrown..
--------------
****SPRING AOP**** DoBeforeMethod : Executing before method!
****SPRING AOP**** DoAroundMethod: Method name : sayHello
****SPRING AOP**** DoAroundMethod: Method arguments : [Javacodegeeks]
****SPRING AOP**** DoAroundMethod: Before method executing!
SimpleService : Method sayHello() : Hello! Javacodegeeks
****SPRING AOP**** DoAroundMethod: After method executing!
****SPRING AOP**** DoAfterReturningMethod : Executing after method return!

4. Create a Pointcut and an Advisor

The Pointcut indicates which method should be intercepted whereas the Advisor groups the Advice and the Pointcut into a single unit, and passes it to a proxy factory object.

There are two types of Pointcuts, the ones that match a method by its name and the ones that match a method using a regular expression pattern. Let’s see how both types of Pointcuts can be used.

4.1 name match pointcut

In order to create a new Pointcut that will match a method by its name, we have to define it as a bean of NameMatchMethodPointcut type in applicationContext.xml. In its property mappedName, the value to be set is the name of the method that will be intercepted. Here, we will intercept sayHello(String message) method.

We must also define the advisor as a bean of DefaultPointcutAdvisor type, here simpleAdvisor bean. Its properties are pointcut and advice and their values are references to the beans of the advice and the pointcut that will be used.

Finally, in simpleServiceProxy bean we must replace the doAroundMethodBean value of interceptorNames property with the simpleAdvisor.

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.javacodegeeks.snippets.enterprise.SimpleService">
		<property name="name" value="Hello" />
		<property name="id" value="12345" />
	</bean>

<bean id="doAroundMethodBean"
		class="com.javacodegeeks.snippets.enterprise.aop.DoAroundMethod" />

	<bean id="simplePointcut" class="org.springframework.aop.support.NameMatchMethodPointcut">
		<property name="mappedName" value="sayHello" />
	</bean>
	<bean id="simpleAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
		<property name="pointcut" ref="simplePointcut" />
		<property name="advice" ref="doAroundMethodBean" />
	</bean>

	<bean id="simpleServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
		<property name="target" ref="simpleServiceBean" />
		<property name="interceptorNames">
			<list>
				<value>simpleAdvisor</value> 
			</list>
		</property>
	</bean>
</beans>

We run the App.class again. Now, only the sayHello(String message) method is being intercepted.

Output

SimpleService : Method printNameId() : My name is Hello and my id is 12345
--------------
SimpleService: Method checkName() exception thrown..
--------------
****SPRING AOP**** DoAroundMethod: Method name : sayHello
****SPRING AOP**** DoAroundMethod: Method arguments : [Javacodegeeks]
****SPRING AOP**** DoAroundMethod: Before method executing!
SimpleService : Method sayHello() : Hello! Javacodegeeks
****SPRING AOP**** DoAroundMethod: After method executing!

Alternatively, you can use the NameMatchMethodPointcutAdvisor, to combine both pointcut and advisor bean definitions in one bean, as shown below:

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.javacodegeeks.snippets.enterprise.SimpleService">
		<property name="name" value="Hello" />
		<property name="id" value="12345" />
	</bean>

<bean id="doAroundMethodBean"
		class="com.javacodegeeks.snippets.enterprise.aop.DoAroundMethod" />
	
	<bean id="simpleAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
		<property name="mappedName" value="sayHello" />
		<property name="advice" ref="doAroundMethodBean" />
	</bean>

	<bean id="simpleServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
		<property name="target" ref="simpleServiceBean" />
		<property name="interceptorNames">
			<list>
				<value>simpleAdvisor</value> 
			</list>
		</property>
	</bean>
</beans>

4.2 regex match pointcut

Now, in order to create a pointcut that matches the method to be intercepted with a regular exression, we must define a new bean of RegexpMethodPointcutAdvisor type. The specific type of advisor has two properties. The patterns property holds a list of the patterns that are used for selecting the methods by their names that will be intercepted and applied the advice code. Here, in regexAdvisor we have used the *Hello* pattern, so again the sayHello(String message) method will be intercepted. The advice property holds a reference to the bean of the advice.

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.javacodegeeks.snippets.enterprise.SimpleService">
		<property name="name" value="Hello" />
		<property name="id" value="12345" />
	</bean>

<bean id="doAroundMethodBean"
		class="com.javacodegeeks.snippets.enterprise.aop.DoAroundMethod" />

	<bean id="regexAdvisor"
		class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
		<property name="patterns">
			<list>
				<value>.*Hello.*</value>
			</list>
		</property>
		<property name="advice" ref="doAroundMethodBean" />
	</bean>

	<bean id="simpleServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
		<property name="target" ref="simpleServiceBean" />
		<property name="interceptorNames">
			<list>
				<value>regexAdvisor</value>
			</list>
		</property>
	</bean>
</beans>

After running App.java class again we can see that only the method whose name matches the pattern *Hello* is being intercepted by the advice. The result is shown below:

Output

SimpleService : Method printNameId() : My name is Hello and my id is 12345
--------------
SimpleService: Method checkName() exception thrown..
--------------
****SPRING AOP**** DoAroundMethod: Method name : sayHello
****SPRING AOP**** DoAroundMethod: Method arguments : [Javacodegeeks]
****SPRING AOP**** DoAroundMethod: Before method executing!
SimpleService : Method sayHello() : Hello! Javacodegeeks
****SPRING AOP**** DoAroundMethod: After method executing!

5. AOP interceptors sequence

Now, let’s see how the sequence of the values in interceptorNames property of the proxy object can affect the sequence in which the advices intercept the methods. We create a new Around method advice, DoAroundMethod2.java class and add it to applicationContext.xml as shown below:

DoAroundMethod2.java

package com.javacodegeeks.snippets.enterprise.aop;

	import java.util.Arrays;
	 
	import org.aopalliance.intercept.MethodInterceptor;
	import org.aopalliance.intercept.MethodInvocation;

public class DoAroundMethod2 implements MethodInterceptor {
		public Object invoke(MethodInvocation methodInvocation) throws Throwable {
	 
			System.out.println("****SPRING AOP**** DoAroundMethod 2: Method name : "
					+ methodInvocation.getMethod().getName());
			System.out.println("****SPRING AOP**** DoAroundMethod 2: Method arguments : "
					+ Arrays.toString(methodInvocation.getArguments()));
			// same with MethodBeforeAdvice
			System.out.println("****SPRING AOP**** DoAroundMethod 2: Before method executing!");
	 
			try {
				// proceed to original method call
				Object result = methodInvocation.proceed();
				// same with AfterReturningAdvice
				System.out.println("****SPRING AOP**** DoAroundMethod 2: After method executing!");
				return result;
	 
			} catch (IllegalArgumentException e) {
				// same with ThrowsAdvice
				System.out.println("****SPRING AOP**** DoAroundMethod 2: When method throws Exception!");
				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.javacodegeeks.snippets.enterprise.SimpleService">
		<property name="name" value="Hello" />
		<property name="id" value="12345" />
	</bean>

	<bean id="doAroundMethodBean" class="com.javacodegeeks.snippets.enterprise.aop.DoAroundMethod" />

	<bean id="doAroundMethod2Bean" class="com.javacodegeeks.snippets.enterprise.aop.DoAroundMethod2" />

	<bean id="simpleServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
		<property name="target" ref="simpleServiceBean" />
		<property name="interceptorNames">
			<list>
				<value>doAroundMethodBean</value>
				<value>doAroundMethod2Bean</value>
			</list>
		</property>
	</bean>
</beans>

When running the application we can see that the around method advice whose bean is defined first in simpleServiceProxy is the one that intercepts the methods first.

Output

****SPRING AOP**** DoAroundMethod: Method name : printNameId
****SPRING AOP**** DoAroundMethod: Method arguments : []
****SPRING AOP**** DoAroundMethod: Before method executing!
****SPRING AOP**** DoAroundMethod 2: Method name : printNameId
****SPRING AOP**** DoAroundMethod 2: Method arguments : []
****SPRING AOP**** DoAroundMethod 2: Before method executing!
SimpleService : Method printNameId() : My name is Hello and my id is 12345
****SPRING AOP**** DoAroundMethod 2: After method executing!
****SPRING AOP**** DoAroundMethod: After method executing!
--------------
****SPRING AOP**** DoAroundMethod: Method name : checkName
****SPRING AOP**** DoAroundMethod: Method arguments : []
****SPRING AOP**** DoAroundMethod: Before method executing!
****SPRING AOP**** DoAroundMethod 2: Method name : checkName
****SPRING AOP**** DoAroundMethod 2: Method arguments : []
****SPRING AOP**** DoAroundMethod 2: Before method executing!
****SPRING AOP**** DoAroundMethod 2: When method throws Exception!
****SPRING AOP**** DoAroundMethod: When method throws Exception!
SimpleService: Method checkName() exception thrown..
--------------
****SPRING AOP**** DoAroundMethod: Method name : sayHello
****SPRING AOP**** DoAroundMethod: Method arguments : [Javacodegeeks]
****SPRING AOP**** DoAroundMethod: Before method executing!
****SPRING AOP**** DoAroundMethod 2: Method name : sayHello
****SPRING AOP**** DoAroundMethod 2: Method arguments : [Javacodegeeks]
****SPRING AOP**** DoAroundMethod 2: Before method executing!
SimpleService : Method sayHello() : Hello! Javacodegeeks
****SPRING AOP**** DoAroundMethod 2: After method executing!
****SPRING AOP**** DoAroundMethod: After method executing!

Now, let’s change the sequence of the interceptors in simpleServiceProxy bean and see what happens:

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.javacodegeeks.snippets.enterprise.SimpleService">
		<property name="name" value="Hello" />
		<property name="id" value="12345" />
	</bean>

	<bean id="doAroundMethodBean" class="com.javacodegeeks.snippets.enterprise.aop.DoAroundMethod" />

	<bean id="doAroundMethod2Bean" class="com.javacodegeeks.snippets.enterprise.aop.DoAroundMethod2" />

	<bean id="simpleServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
		<property name="target" ref="simpleServiceBean" />
		<property name="interceptorNames">
			<list>
				<value>doAroundMethod2Bean</value>
				<value>doAroundMethodBean</value>
			</list>
		</property>
	</bean>
</beans>

Again, the first defined interceptor is the one that intercepts the methods first:

Output

****SPRING AOP**** DoAroundMethod 2: Method name : printNameId
****SPRING AOP**** DoAroundMethod 2: Method arguments : []
****SPRING AOP**** DoAroundMethod 2: Before method executing!
****SPRING AOP**** DoAroundMethod: Method name : printNameId
****SPRING AOP**** DoAroundMethod: Method arguments : []
****SPRING AOP**** DoAroundMethod: Before method executing!
SimpleService : Method printNameId() : My name is Hello and my id is 12345
****SPRING AOP**** DoAroundMethod: After method executing!
****SPRING AOP**** DoAroundMethod 2: After method executing!
--------------
****SPRING AOP**** DoAroundMethod 2: Method name : checkName
****SPRING AOP**** DoAroundMethod 2: Method arguments : []
****SPRING AOP**** DoAroundMethod 2: Before method executing!
****SPRING AOP**** DoAroundMethod: Method name : checkName
****SPRING AOP**** DoAroundMethod: Method arguments : []
****SPRING AOP**** DoAroundMethod: Before method executing!
****SPRING AOP**** DoAroundMethod: When method throws Exception!
****SPRING AOP**** DoAroundMethod 2: When method throws Exception!
SimpleService: Method checkName() exception thrown..
--------------
****SPRING AOP**** DoAroundMethod 2: Method name : sayHello
****SPRING AOP**** DoAroundMethod 2: Method arguments : [Javacodegeeks]
****SPRING AOP**** DoAroundMethod 2: Before method executing!
****SPRING AOP**** DoAroundMethod: Method name : sayHello
****SPRING AOP**** DoAroundMethod: Method arguments : [Javacodegeeks]
****SPRING AOP**** DoAroundMethod: Before method executing!
SimpleService : Method sayHello() : Hello! Javacodegeeks
****SPRING AOP**** DoAroundMethod: After method executing!
****SPRING AOP**** DoAroundMethod 2: After method executing!

6. AOP auto proxy creators

An interesting feature of Spring is that it provides two auto proxy creators, so that we can create proxies for our beans automatically.

6.1 BeanNameAutoProxyCreator

The first auto proxy creator Spring provides is the BeanNameAutoProxyCreator that automatically creates AOP proxies for beans with names matching literal values or wildcards. In order to use it we must define it in applicationContext.xml. This creator exposes two properties for us to configure. The first property is beanNames and its value is a list of regular expressions matching the Spring bean names (ids) to be proxied. The second property is interceptorNames and its value is a list of the advisors (Spring bean ids) that will be used.

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.javacodegeeks.snippets.enterprise.SimpleService">
		<property name="name" value="Hello" />
		<property name="id" value="12345" />
	</bean>

	<bean id="doAroundMethodBean" class="com.javacodegeeks.snippets.enterprise.aop.DoAroundMethod" />

	<bean id="simplePointcut" class="org.springframework.aop.support.NameMatchMethodPointcut">
		<property name="mappedName" value="sayHello" />
	</bean>

	<bean id="simpleAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
		<property name="mappedName" value="sayHello" />
		<property name="advice" ref="doAroundMethodBean" />
	</bean>
	<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
		<property name="beanNames">
			<list>
				<value>*ServiceBean</value>
			</list>
		</property>
		<property name="interceptorNames">
			<list>
				<value>simpleAdvisor</value>
			</list>
		</property>
	</bean>
</beans>

Now we can load the simpleServiceBean in App.java class, without having to know if this bean has a proxy object or not. The BeanNameAutoProxyCreator will load the proxy.
App.java

package com.javacodegeeks.snippets.enterprise;

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

public class App {

	public static void main(String[] args) {
	
			ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
			SimpleService simpleService = (SimpleService) context.getBean("simpleServiceBean");
			simpleService.printNameId();
			System.out.println("--------------");
			try{
				simpleService.checkName();
			} catch(Exception e){
				System.out.println("SimpleService: Method checkName() exception thrown..");
			}
			System.out.println("--------------");
			simpleService.sayHello("Javacodegeeks");
			context.close();
	}
}

The output is shown below:
Output

SimpleService : Method printNameId() : My name is Hello and my id is 12345
--------------
SimpleService: Method checkName() exception thrown..
--------------
****SPRING AOP**** DoAroundMethod: Method name : sayHello
****SPRING AOP**** DoAroundMethod: Method arguments : [Javacodegeeks]
****SPRING AOP**** DoAroundMethod: Before method executing!
SimpleService : Method sayHello() : Hello! Javacodegeeks
****SPRING AOP**** DoAroundMethod: After method executing!

6.2 DefaultAdvisorAutoProxyCreator

The second auto proxy creator Spring provides is the DefaultAdvisorAutoProxyCreator that automatically applies advisors in the current applicationContext.xml, without the need to include specific bean names in the auto-proxy advisor’s bean definition. In order to use it we must specify a DefaultAdvisorAutoProxyCreator bean definition in applicationContext.xml. Then we must specify any number of advisors in the same or related configuration files. The DefaultAdvisorAutoProxyCreator will automatically evaluate the pointcut contained in each advisor, to see what (if any) advice it should apply to each object.

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.javacodegeeks.snippets.enterprise.SimpleService">
		<property name="name" value="Hello" />
		<property name="id" value="12345" />
	</bean>

	<bean id="doAroundMethodBean" class="com.javacodegeeks.snippets.enterprise.aop.DoAroundMethod" />


	<bean id="simplePointcut" class="org.springframework.aop.support.NameMatchMethodPointcut">
		<property name="mappedName" value="sayHello" />
	</bean>

	<bean id="simpleAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
		<property name="mappedName" value="sayHello" />
		<property name="advice" ref="doAroundMethodBean" />
	</bean>
	
	<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />

</beans>

After running App.java class again the result is shown below:

Output

SimpleService : Method printNameId() : My name is Hello and my id is 12345
--------------
SimpleService: Method checkName() exception thrown..
--------------
****SPRING AOP**** DoAroundMethod: Method name : sayHello
****SPRING AOP**** DoAroundMethod: Method arguments : [Javacodegeeks]
****SPRING AOP**** DoAroundMethod: Before method executing!
SimpleService : Method sayHello() : Hello! Javacodegeeks
****SPRING AOP**** DoAroundMethod: After method executing!

 
This was an example of Aspect Oriented Programming in Spring.
Download the Eclipse project of this tutorial : SpringAOPExample.zip

Theodora Fragkouli

Theodora has graduated from Computer Engineering and Informatics Department in the University of Patras. She also holds a Master degree in Economics from the National and Technical University of Athens. During her studies she has been involved with a large number of projects ranging from programming and software engineering to telecommunications, hardware design and analysis. She works as a junior Software Engineer in the telecommunications sector where she is mainly involved with projects based on Java and Big Data technologies.
Subscribe
Notify of
guest

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

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button