Aspect Oriented Programming in Spring 2.5

Part One: Introduction to Spring AOP and proxies

by Christophe Verré

Advices, pointcuts. Obscure words making me wonder what Aspect-Oriented Programming (AOP) is all about. In fact, behind these words lie very simple principles. Once the AOP vocabulary has been tackled, using AOP is a matter of practice. Spring offers different techniques to use AOP, but I think that the variety of choice makes AOP even more confusing. Let's clear this up, and see how AOP can be used in Spring.

Two AOP implementations can be chosen, as well as two coding styles for each. Confusing, isn't it ?

Annotations can be used with Java5+. I recommend to go through Spring's reference documentation to decide which one to choose. It will mainly depend on requirements and taste. I think that understanding Spring AOP is a priority before thinking of using AspectJ. In this tutorial, we will use Spring AOP only, using both the @AspectJ and XML styles. It is assumed that you are already comfortable with Spring's dependency injection. If not, you can read this tutorial first. Basic database knowledge will help too.

AOP, what's the big deal ?

AOP is here to help programmers to separate of crosscutting concerns. What's that ? Imagine ordering an item at an online shop. When the item is ordered, several database tables may be updated. If a problem occurs during the ordering process, everything sent to the database should be cancelled (rollback). If the ordering process successfully ends, the ordering should be committed to the databases.

[Before]

public class OrderServiceImpl implements OrderService {
    public void orderItem(Item item, int quantity) {
        // Insert item into ORDER table
        ...
        // Update ITEM table, decrement the number of remaining items
        ...
    }
    ...
}

public class OrderItem {
    public void orderItem(Item item, int quantity) {        
        OrderService orderService = ServiceManager.getOrderService();
        orderService.orderItem(item, quantity);
    }
}

[After]

public class OrderServiceImpl implements OrderService {
    public void orderItem(Item item, int quantity) {
        // Start transaction
        ...
        // Insert item into ORDER table
        ...
        // Update ITEM table, decrement the number of remaining items
        ...
        // Commit changes
        ...
    }
}

public class OrderItem {
    public void orderItem(Item item, int quantity) {
        try {
            OrderService orderService = ServiceManager.getOrderService();
            orderService.orderItem(item, quantity);
        } catch( DbException e ) {
            // log exception
            ...
            // Rollback transaction
            ...
        }
    }
}
All this changes to make one transaction ! And that's just the orderItem() method. All methods that need transactions will look like this. The OrderServiceImpl's primary objective is only to fetch, insert, update or delete users. It doesn't care about transactions after all. If transactions could magically start when needed, without the OrderServiceImpl knowing it. Wouldn't it be great if transactions could be implemented without touching the original object ? That is where AOP comes to the rescue. A transaction is a crosscutting concern. It may be applied anywhere on top of existing code. Spring not only supports AOP, but also offers a very useful transaction management system. But before diving into AOP, let's first see an important concept in Spring AOP: proxies.

Proxy

A proxy is a well-used design pattern. To put it simply, a proxy is an object that looks like another object, but adds special functionality behind the scene. In Spring, any interface can be proxied. Let's see a simple example to illustrate what a proxy really is. The Saloon interface:
package com.javaranch.journal.spring.aop;

public interface Saloon {    
        
    void openSaloon();
}
A simple implementation of the Saloon, the MooseSaloon :
package com.javaranch.journal.spring.aop;

public class MooseSaloon implements Saloon {

    /** Welcome message */
    private String greeting;
    
    public void setGreeting(String greeting) {
        this.greeting = greeting;
    }
    
    public void openSaloon() {        
        System.out.println("Saloon open [" + getClass() + "/" + toString() + "]");
        System.out.println(greeting);
    }
    
}
The MooseSaloon declared as a simple bean, and a proxy to the MooseSaloon:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

    <bean id="mooseSaloon" class="com.javaranch.journal.spring.aop.MooseSaloon">
        <property name="greeting"><value>Welcome to the Big Moose Saloon !!</value></property>
    </bean>
    
    <bean id="proxySaloon" 
        class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="proxyInterfaces"><value>com.javaranch.journal.spring.aop.Saloon</value></property>    
        <property name="target"><ref local="mooseSaloon"/></property>
    </bean>
</beans>
The Main class using both the MooseSaloon and its proxy:
package com.javaranch.journal.spring.aop;

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

public class Main {

    public static void main(String[] args) {

        ApplicationContext ctx = new ClassPathXmlApplicationContext("aop.xml");
        // The mooseSaloon pojo
        Saloon mooseSaloon = (Saloon)ctx.getBean("mooseSaloon");
        mooseSaloon.openSaloon();
        System.out.println("mooseSaloon [" + mooseSaloon.getClass() + "]");
        System.out.println("--------");
        // The mooseSaloon proxy
        Saloon proxySaloon = (Saloon)ctx.getBean("proxySaloon");
        proxySaloon.openSaloon();
        System.out.println("proxySaloon [" + proxySaloon.getClass() + "]");
    }
}
Running this application will produce something similar to the following output :

Saloon open [class com.javaranch.journal.spring.aop.MooseSaloon/
        com.javaranch.journal.spring.aop.MooseSaloon@bfea1d]
Welcome to the Big Moose Saloon !!
mooseSaloon [class com.javaranch.journal.spring.aop.MooseSaloon]
--------
Saloon open [class com.javaranch.journal.spring.aop.MooseSaloon/
        com.javaranch.journal.spring.aop.MooseSaloon@bfea1d]
Welcome to the Big Moose Saloon !!
proxySaloon [class $Proxy0]

You can notice that both the MooseSaloon and its proxy do the same thing. However, both mooseSaloon and proxySaloon are different classes. The proxy holds a reference to the mooseSaloon and implements the same interface, thus it holds the same methods implemented by MooseSaloon. What you cannot see yet is that the proxy can add some nifty functionality behind the hood. But before getting deeper into AOP, let's see some important terminology.

AOP jargon

The AOP terminology may be boring to get on with, but it is necessary to understand these words before going further. When an aspect is applied to an object, a particular advice will be applied to any join point matching a pointcut's expression. Starting a transaction could be expressed the following way : NOTE: In Spring AOP, only the "execute method" join point is supported.

There are different types of advices

A simple advice

In the MooseSaloon example, let's apply a simple aspect : Don't worry about ProxyBeanFactory and MethodBeforeAdvice gorry details. The point here is just to illustrate what a proxy does behind the scene. Here is the advice we will apply to our saloon.
package com.javaranch.journal.spring.aop;

import java.lang.reflect.Method;
import java.util.Date;

import org.springframework.aop.MethodBeforeAdvice;

public class SaloonWatcher implements MethodBeforeAdvice {

    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("[" + new Date() + "]" + method.getName() + " called on " + target);
    }
}
The MethodBeforeAdvice's before() method will be called before a method of a target bean is called.

Let's now modify the proxy to use this advice:
<bean id="proxySaloon" 
    class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="proxyInterfaces"><value>com.javaranch.journal.spring.aop.Saloon</value></property>    
    <property name="target"><ref local="mooseSaloon"/></property>
    <property name="interceptorNames">
        <list>
            <value>saloonWatcher</value>
        </list>
    </property>
</bean>

That's all. The Main class and the MooseSaloon class do not change. After execution, the printed information will look like this:

Saloon open [class com.javaranch.journal.spring.aop.MooseSaloon/
        com.javaranch.journal.spring.aop.MooseSaloon@bfea1d]
Welcome to the Big Moose Saloon !!
mooseSaloon [class com.javaranch.journal.spring.aop.MooseSaloon]
--------
[Mon Mar 24 15:14:42 JST 2008]openSaloon called on com.javaranch.journal.spring.aop.MooseSaloon@2a4983
Saloon open [class com.javaranch.journal.spring.aop.MooseSaloon/
        com.javaranch.journal.spring.aop.MooseSaloon@bfea1d]
Welcome to the Big Moose Saloon !!
proxySaloon [class $Proxy0]

Isn't that magic ? Not really, it's called AOP, using a proxy. Although the MooseSaloon class was not changed, we managed to report when a Saloon method is called. Can you now imagine how to manage transactions without modifying the existing code ?

A word on proxying beans

In the above example, there is a MooseSaloon and its proxy. In the main method, the proxy is explicitly instanciated via its name "proxySaloon". Wouldn't it be cool if we could use a proxy without even knowing it ? Actually, Spring uses a powerful feature called autoproxying, which will proxy selected beans behind the scene. There are different ways to achieve this. Here is one using the BeanNameAutoProxyCreator, which automatically create proxies depending on bean names. In part two of this tutorial, we will see how autoproxying is achieved using the @AspectJ annotations. But to illustrate the concept of autoproxying, let's modify the Main class, the bean definition file, and use a BeanNameAutoProxyCreator. Let's remove the proxy from the Main class.
package com.javaranch.journal.spring.aop;

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

public class Main {

    public static void main(String[] args) {

        ApplicationContext ctx = new ClassPathXmlApplicationContext("aop.xml");
        // The mooseSaloon pojo
        Saloon mooseSaloon = (Saloon)ctx.getBean("mooseSaloon");
        mooseSaloon.openSaloon();
        System.out.println("mooseSaloon [" + mooseSaloon.getClass() + "]");
    }
}

And let's remove it from the definition file too. Instead, we will use the BeanNameAutoProxyCreator to create a proxy automatically on the MooseSaloon.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

    <bean id="mooseSaloon" class="com.javaranch.journal.spring.aop.MooseSaloon">
        <property name="greeting"><value>Welcome to the Big Moose Saloon !!</value></property>
    </bean>

    <bean id="saloonWatcher" class="com.javaranch.journal.spring.aop.SaloonWatcher" />
    
    <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
      <property name="beanNames"><value>*Saloon</value></property>
      <property name="interceptorNames">
        <list>
          <value>saloonWatcher</value>
        </list>
      </property>
    </bean>
</beans>

A proxy will be created for every bean whose name ends in "Saloon", just like our "mooseSaloon". After executing this new version, something similar to the following should be printed:

[Mon Mar 24 16:00:56 JST 2008]openSaloon called on com.javaranch.journal.spring.aop.MooseSaloon@5a9de6
Saloon open [class com.javaranch.journal.spring.aop.MooseSaloon/
        com.javaranch.journal.spring.aop.MooseSaloon@5a9de6]
Welcome to the Big Moose Saloon !!
mooseSaloon [class $Proxy0]

Amazing, isn't it ? Look at the Main class. Although the "mooseSaloon" bean is obtained from the factory, the log information has been printed out. The class name is not MooseSaloon, but "$Proxy0". This shows that we are working on the proxy, not the bean itself.

You've made it

Congratulations, you've made it ! Don't think too much about MethodBeforeAdvice, ProxyBeanFactory or BeanNameAutoProxyCreator. These were used in Spring 1.2, but there are now other ways to use proxies and AOP since Spring 2.0, which will be the subject of this tutorial's next part. If you have understood what a proxy is, and still remember what the AOP main keywords are, you're fine for now.