Simple Spring

In this tutorial we will create, from the very beginning, a simple application that uses Spring and its Aspect Oriented Programming capabilities. We will use schema-based approach from Spring 2.0 to define the AOP configuration.
I am not going to cover here the AOP or Spring basis, if you are interested what AOP is or why would you use it, try documentation on Spring or AspectJ website.

Let’s create a very simple class – we will base all the examples on it:

package techblog.zabuchy.net;
 
public class Person
{
	private String name;
	private String website;
 
	public void setName(String name) {
		this.name = name;
	}
 
	public void setWebsite(String website) {
		this.website = website;
	}
 
	public void printName(){
		System.out.println("My name: " + this.name);
	}
 
	public void printWebsite(){
		System.out.println("My website: " + this.website);
		privateMethod();
                publicMethod();
	}
 
	private void privateMethod() {
		System.out.println("Private method");
	}
 
	private void publicMethod() {
		System.out.println("Public method");
	}
	public void throwException(){
		throw new IllegalArgumentException();
	}
}

We also need a main class that we’ll be running – again, very simple one will be enough:

package techblog.zabuchy.net;
 
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
public class App {
	public static void main(String[] args) {
		ApplicationContext appContext = new ClassPathXmlApplicationContext(
				new String[] { "spring.xml" });
 
		Person me = (Person) appContext.getBean("person");
 
		System.out.println("About to print a name...");
		me.printName();
 
		System.out.println("About to print a website...");
		me.printWebsite();
 
		System.out.println("About to throw an exception...");
		try {
			me.throwException();
		} catch (Exception e) {
 
		}
	}
}

Our spring.xml contains a definition of person bean:

<bean id="person" class="techblog.zabuchy.net.Person">
		<property name="name" value="Tomasz Muras" />
		<property name="website" value="http://techblog.zabuchy.net" />
	</bean>

Aspect Oriented Programming with Spring

It’s all nice & easy so far – but let’s add AOP to that mix. We basically need two things:

  • We need the functionality/feature/concern that needs to run across different classes – using proper terminology we need our aspect.
  • We need to tell (advice) Spring when this aspect should run. The first bit is very simple – aspect can simply be a class with a method:
package techblog.zabuchy.net;
 
public class InjectMe {
	public void injectMethod() {
		System.out.println("INJECT!");
	}
}

The second bit will be defined declaratively in our spring.xml. First we need our “aspect class” as a normal bean:

<bean id="inject" class="techblog.zabuchy.net.InjectMe" />

Then we declare AOP behavior – all is wrapped in <aop:config> tag (I’ll cover aop namespace shortly). We need to refer to our inject bean:

<aop:config>
<aop:aspect ref="inject">
...
</aop:aspect>
</aop:config>

Then we need to say when it should run. The when in Spring is simple – it always refers to some method execution. In our example, we would like to run our InjectMe class when any method from Person is executed – in AOP terminology it means we need to define a pointcut that refers to all those methods:

<aop:config>
<aop:aspect ref="inject">
<aop:pointcut expression="execution(* techblog.zabuchy.net.Person.*(..))" id="pointcut1" />
....
</aop:aspect>
</aop:config>

The pointcut simply points to the methods, we need to specify when exactly aspect should run (before the method executes or maybe after?). We also need to say which method of our inject bean is to be executed:

<aop:config>
<aop:aspect ref="inject">
<aop:pointcut expression="execution(* techblog.zabuchy.net.Person.*(..))" id="pointcut1" />
<aop:before method="injectMethod" pointcut-ref="pointcut1" />
</aop:aspect>
</aop:config>

That’s it! When we run the example, the output will look like below:

About to print a name...
INJECT!
My name: Tomasz Muras
About to print a website...
INJECT!
My website: http://techblog.zabuchy.net
Private method
Public method
About to throw an exception...
INJECT!

Notice that the aspect was run 3 times – and we have run 3 public methods on an object of Person class. When object executes its own method, AOP did not work. To complete Spring’s XML file, we need to add aop namespace and schema. The full spring.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
	http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
 
	<bean id="inject" class="techblog.zabuchy.net.InjectMe" />
 
	<bean id="person" class="techblog.zabuchy.net.Person">
		<property name="name" value="Tomasz Muras" />
		<property name="website" value="http://techblog.zabuchy.net" />
	</bean>
 
	<aop:config>
		<aop:aspect ref="inject">
			<aop:pointcut expression="execution(* techblog.zabuchy.net.Person.*(..))"
				id="pointcut1" />
			<aop:before method="injectMethod" pointcut-ref="pointcut1" />
		</aop:aspect>
	</aop:config>
</beans>

Run after returning from a method

If we would like to execute the aspect after the method is run, we replace element with . Since the method executed already, we can also get hold of the return value. To do so, we’ll declare our aspect method with an extra argument:

public class InjectMe {
	public void injectAfter(Object ret) {
		System.out.println("INJECT AFTER! Returned: " + ret);
	}
}

Updated XML file:

<aop:config>
		<aop:aspect ref="inject">
			<aop:pointcut expression="execution(* techblog.zabuchy.net.Person.*(..))"
				id="pointcut1" />
			<aop:after-returning returning="ret" method="injectAfter" pointcut-ref="pointcut1" />
		</aop:aspect>
	</aop:config>

And the output this time. Note that the aspect did not execute after a method has thrown an exception.

About to print a name...
My name: Tomasz Muras
INJECT AFTER! Returned: null
About to print a website...
My website: http://techblog.zabuchy.net
Private method
Public method
INJECT AFTER! Returned: null
About to throw an exception...

Run after an exception is thrown and run always (finally)

You can also run aspect only after a method throws an exception with <aop:after-throwing> element or in both cases using <aop:after>. You will find the examples of both in the attached source code.

Run before and after the exception

The most powerful advice is <aop:around>. It runs both before and after method execution and it gives you the opportunity to cancel method execution altogether.
The schema definition looks just like for previous advices:

	<aop:config>
		<aop:aspect ref="inject">
			<aop:pointcut expression="execution(* techblog.zabuchy.net.Person.*(..))"
				id="pointcut1" />
			<aop:around method="injectAround" pointcut-ref="pointcut1" />
		</aop:aspect>
	</aop:config>

Advice method must have the first argument of type org.aspectj.lang.ProceedingJoinPoint. When/if we decide to run the actual method, we run proceed() method on the ProceedingJoinPoint object.

	public Object injectAround(ProceedingJoinPoint pjp) throws Throwable {
		// do some logic before
		System.out.println("INJECT BEFORE!");
 
		// run the actual method
		Object retVal = null;
		try {
			retVal = pjp.proceed();
		} catch (Exception e) {
 
		}
 
		// more logic after method executes
		System.out.println("INJECT AFTER!");
		return retVal;
	}

Source code and dependencies

You can download full source code with all the examples above. Here is a list of jars I’ve used for compiling the example:

  • spring-aop-3.0.4.RELEASE.jar
  • spring-beans-3.0.4.RELEASE.jar
  • spring-context-3.0.4.RELEASE.jar
  • spring-core-3.0.4.RELEASE.jar
  • spring-expression-3.0.4.RELEASE.jar
  • spring-test-3.0.4.RELEASE.jar
  • spring-tx-3.0.4.RELEASE.jar
  • spring-asm-3.0.4.RELEASE.jar
  • commons-logging-1.1.1.jar
  • aopalliance-1.0.jar
  • cglib-2.2.jar
  • asm-3.1.jar
  • spectjrt.jar
  • aspectjtools.jar
  • org.aspectj.matcher.jar
  • log4j-1.2.16.jar