Spring AOP (Aspect Oriented Programming) Example

With this tutorial we will see how to use Aspect Oriented Programming in Spring Framework. AOP is used in the Spring Framework to provide declarative enterprise 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 Kepler version. We are also using Spring version 3.2.8 and the JDK 1.6.

Make sure you have the list of required jar files in your classpath.
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 show an example for each one of them.

AOPService.java class is the class whose methods will be intercepted by the advices

package in.sblog.spring.aop.service;
public class AOPService {
    private int aopId;
    private String aopName;
    public int getAopId() {
        return aopId;
    }
    public void setAopId(int aopId) {
        this.aopId = aopId;
    }
    public String getAopName() {
        return aopName;
    }
    public void setAopName(String aopName) {
        this.aopName = aopName;
    }
    public void printAOPName() {
        System.out.println("inside AOPService::printAOPName.");
        System.out.println("AOP Id:" + aopId + ", AOP Name: " + aopName);
        System.out.println();
    }
    public void isValidNameLength() {
        if (aopName != null || !aopName.trim().isEmpty()) {
            if (aopName.trim().length() < 6 || aopName.trim().length() > 25) {
                throw new IllegalArgumentException(
                        "Name must not less than 3 chars and greater than 25 chars long!");
            } else {
                System.out.println("Name is valid!");
            }
        } else {
            throw new IllegalArgumentException("Name canot be null!");
        }
        System.out.println();
    }
    public void printAnyMessage(String msg) {
        System.out.println("Message: " + msg);
    }
}

 
Before Advice

Before Advice executes before a method execution, but it does not have the ability to prevent execution flow proceeding to the method execution unless the method throws an exception. Our class has to implement the interface MethodBeforeAdvice.

package in.sblog.spring.aop.advice;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class AOPBeforeMethod implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] args, Object target)
            throws Throwable {
        System.out.println("AOPBeforeMethod.before() overrides MethodBeforeAdvice.before()");
        System.out.println("Method which gets executed: " + method.getName());
        if (args.length > 0) {
            System.out.println("Arguments passed to the method:");
            for (int i = 0; i < args.length; i++) {
                System.out.println("args[" + i + "]: " + args[i]);
            }
        }
        System.out.println("Target where the advice is applied on: " + target);
        System.out.println();
    }
}

 

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.

<?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: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="aopServiceBean" class="in.sblog.spring.aop.service.AOPService">
        <property name="aopId" value="1000"></property>
        <property name="aopName" value="sblog.in"></property>
    </bean><bean id="aopBeforeMethodBean" class="in.sblog.spring.aop.advice.AOPBeforeMethod"></bean><bean id="aopServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="aopServiceBean"></property>
        <property name="interceptorNames">
            <list>
                <value>aopBeforeMethodBean</value>
            </list>
        </property>
    </bean>
</beans>

 

We must load the aopServiceProxy bean in TestAOP.java in order to run the application, as shown below:

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestAOP {
    public static void main(String[] args) {
        @SuppressWarnings("resource")
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
                "aopContext.xml");
        AOPService aopService = (AOPService) applicationContext
                .getBean("aopServiceProxy");
        System.out.println("--------------------------------------------");
        aopService.printAOPName();
        System.out.println("--------------------------------------------");
        System.out.println();
        System.out.println("--------------------------------------------");
        aopService.isValidNameLength();
        System.out.println("--------------------------------------------");
        System.out.println();
        System.out.println("--------------------------------------------");
        aopService.printAnyMessage("from www.sblog.in tutorial");
        System.out.println("--------------------------------------------");
    }
}

 

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

Output:

--------------------------------------------
AOPBeforeMethod.before() overrides MethodBeforeAdvice.before()
Method which gets executed: printAOPName
Target where the advice is applied on: in.sblog.spring.aop.service.AOPService@23e5d1
inside AOPService::printAOPName.
AOP Id:1000, AOP Name: sblog.in
--------------------------------------------
--------------------------------------------
AOPBeforeMethod.before() overrides MethodBeforeAdvice.before()
Method which gets executed: isValidNameLength
Target where the advice is applied on: in.sblog.spring.aop.service.AOPService@23e5d1
Name is valid!
--------------------------------------------
--------------------------------------------
AOPBeforeMethod.before() overrides MethodBeforeAdvice.before()
Method which gets executed: printAnyMessage
Arguments passed to the method:
args[0]: from www.sblog.in tutorial
Target where the advice is applied on: in.sblog.spring.aop.service.AOPService@23e5d1
Message: from www.sblog.in tutorial
--------------------------------------------

 
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 has to implement the interface AfterReturningAdvice.

import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
public class AOPAfterReturningMethod implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object returnValue, Method method,
            Object[] args, Object target) throws Throwable {
        System.out
                .println("AOPAfterReturningMethod.afterReturning() overrides AfterReturningAdvice.afterReturning()");
        System.out.println("Method which returns: " + returnValue);
        System.out.println("Method which gets executed: " + method.getName());
        if (args.length > 0) {
            System.out.println("Arguments passed to the method:");
            for (int i = 0; i < args.length; i++) {
                System.out.println("args[" + i + "]: " + args[i]);
            }
        }
        System.out.println("Target where the advice is applied on: " + target);
        System.out.println();
    }
}

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

<?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: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="aopServiceBean" class="in.sblog.spring.aop.service.AOPService">
        <property name="aopId" value="1000"></property>
        <property name="aopName" value="sblog.in"></property>
    </bean><bean id="aopBeforeMethodBean" class="in.sblog.spring.aop.advice.AOPBeforeMethod"></bean><bean id="aopAfterReturningMethodBean" class="in.sblog.spring.aop.advice.AOPAfterReturningMethod"></bean><bean id="aopServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="aopServiceBean"></property>
        <property name="interceptorNames">
            <list>
                <value>aopBeforeMethodBean</value>
                <value>aopAfterReturningMethodBean</value>
            </list>
        </property>
    </bean>
</beans>

 

Now, after running TestAOP.java class again we can see that the afterReturning(Object returnValue, Method method, Object[] args, Object target) method of AOPAfterReturningMethod advice is executed after the AOPService‘s methods’ execution.

Output:

--------------------------------------------
AOPBeforeMethod.before() overrides MethodBeforeAdvice.before()
Method which gets executed: printAOPName
Target where the advice is applied on: in.sblog.spring.aop.service.AOPService@b8c8e6
inside AOPService::printAOPName.
AOP Id:1000, AOP Name: sblog.in
AOPAfterReturningMethod.afterReturning() overrides AfterReturningAdvice.afterReturning()
Method which returns: null
Method which gets executed: printAOPName
Target where the advice is applied on: in.sblog.spring.aop.service.AOPService@b8c8e6
--------------------------------------------
--------------------------------------------
AOPBeforeMethod.before() overrides MethodBeforeAdvice.before()
Method which gets executed: isValidNameLength
Target where the advice is applied on: in.sblog.spring.aop.service.AOPService@b8c8e6
Name is valid!
AOPAfterReturningMethod.afterReturning() overrides AfterReturningAdvice.afterReturning()
Method which returns: null
Method which gets executed: isValidNameLength
Target where the advice is applied on: in.sblog.spring.aop.service.AOPService@b8c8e6
--------------------------------------------
--------------------------------------------
AOPBeforeMethod.before() overrides MethodBeforeAdvice.before()
Method which gets executed: printAnyMessage
Arguments passed to the method:
args[0]: from www.sblog.in tutorial
Target where the advice is applied on: in.sblog.spring.aop.service.AOPService@b8c8e6
Message: from www.sblog.in tutorial
AOPAfterReturningMethod.afterReturning() overrides AfterReturningAdvice.afterReturning()
Method which returns: null
Method which gets executed: printAnyMessage
Arguments passed to the method:
args[0]: from www.sblog.in tutorial
Target where the advice is applied on: in.sblog.spring.aop.service.AOPService@b8c8e6
--------------------------------------------

 
After Throwing Advice

After throwing Advice is the Advice to be executed if a method exits by throwing an exception. The class has to implement the ThrowsAdvice interface.

import org.springframework.aop.ThrowsAdvice;
public class AOPAfterThrowingExceptionMethod implements ThrowsAdvice {
    public void afterThrowing(IllegalArgumentException e) {
        System.out.println("AOPAfterThrowingExceptionMethod implements ThrowsAdvice");
        System.out
                .println("Executes when a particular method throws an Exception");
        System.out.println("The exception trace is below:");
        System.out.println(e);
    }
}

 
We add the new bean in aopContext.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: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="aopServiceBean" class="in.sblog.spring.aop.service.AOPService"></pre>
       <property name="aopId" value="1000"></property>
        <property name="aopName" value="sblog"></property>
    </bean><bean id="aopBeforeMethodBean" class="in.sblog.spring.aop.advice.AOPBeforeMethod"></bean><bean id="aopAfterReturningMethodBean" class="in.sblog.spring.aop.advice.AOPAfterReturningMethod"></bean><bean id="aopAOPAfterThrowingExceptionMethodBean" class="in.sblog.spring.aop.advice.AOPAfterThrowingExceptionMethod"></bean><bean id="aopServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="aopServiceBean"></property>
        <property name="interceptorNames">
            <list>
                <value>aopBeforeMethodBean</value>
                <value>aopAfterReturningMethodBean</value>
                <value>aopAOPAfterThrowingExceptionMethodBean</value>
            </list>
        </property>
    </bean>
</beans>

 

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

Output:

--------------------------------------------
AOPBeforeMethod.before() overrides MethodBeforeAdvice.before()
Method which gets executed: printAOPName
Target where the advice is applied on: in.sblog.spring.aop.service.AOPService@176e552
inside AOPService::printAOPName.
AOP Id:1000, AOP Name: sblog
AOPAfterReturningMethod.afterReturning() overrides AfterReturningAdvice.afterReturning()
Method which returns: null
Method which gets executed: printAOPName
Target where the advice is applied on: in.sblog.spring.aop.service.AOPService@176e552
--------------------------------------------
--------------------------------------------
AOPBeforeMethod.before() overrides MethodBeforeAdvice.before()
Method which gets executed: isValidNameLength
Target where the advice is applied on: in.sblog.spring.aop.service.AOPService@176e552
AOPAfterThrowingExceptionMethod implements ThrowsAdvice
Executes when a particular method throws an Exception
The exception trace is below:
java.lang.IllegalArgumentException: Name must not less than 3 chars and greater than 25 chars long!
Exception in thread "main" java.lang.IllegalArgumentException: Name must not less than 3 chars and greater than 25 chars long!
    at in.sblog.spring.aop.service.AOPService.isValidNameLength(AOPService.java:33)
    at in.sblog.spring.aop.service.AOPService$$FastClassBySpringCGLIB$$baddd1d7.invoke()
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:700)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    at org.springframework.aop.framework.adapter.ThrowsAdviceInterceptor.invoke(ThrowsAdviceInterceptor.java:124)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:51)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:51)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:633)
    at in.sblog.spring.aop.service.AOPService$$EnhancerBySpringCGLIB$$6207e9f3.isValidNameLength()
    at in.sblog.spring.aop.test.TestAOP.main(TestAOP.java:22)

 
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 has to implement the interface MethodInterceptor.

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class AOPARoundMethod implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out
                .println("AOPARoundMethod.invoke() overrides MethodInterceptor.invoke()");
        System.out.println("Method which gets executed: "
                + methodInvocation.getMethod().getName());
        if (methodInvocation.getArguments().length > 0) {
            System.out.println("Arguments passed to the method:");
            for (int i = 0; i < methodInvocation.getArguments().length; i++) {
                System.out.println("args[" + i + "]: "
                        + methodInvocation.getArguments()[i]);
            }
        }
        System.out.println("Before Method executing");
        try {
            Object result = methodInvocation.proceed();
            System.out.println("After Method executing");
            return result;
        } catch (Throwable t) {
            System.out.println("When Exceptions are thrown");
            throw t;
        }
    }
}

 

<?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: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="aopServiceBean" class="in.sblog.spring.aop.service.AOPService">
        <property name="aopId" value="1000"></property>
        <property name="aopName" value="sblog.in"></property>
    </bean><bean id="aopBeforeMethodBean" class="in.sblog.spring.aop.advice.AOPBeforeMethod"></bean><bean id="aopAfterReturningMethodBean" class="in.sblog.spring.aop.advice.AOPAfterReturningMethod"></bean><bean id="aopAOPAfterThrowingExceptionMethodBean" class="in.sblog.spring.aop.advice.AOPAfterThrowingExceptionMethod"></bean><bean id="aopAOPAroundMethodBean" class="in.sblog.spring.aop.advice.AOPARoundMethod"></bean><bean id="aopServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="aopServiceBean"></property>
        <property name="interceptorNames">
            <list>
                <value>aopBeforeMethodBean</value>
                <value>aopAfterReturningMethodBean</value>
                <value>aopAOPAfterThrowingExceptionMethodBean</value>
                <value>aopAOPAroundMethodBean</value>
            </list>
        </property>
    </bean>
</beans>

 

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

Output:

--------------------------------------------
AOPBeforeMethod.before() overrides MethodBeforeAdvice.before()
Method which gets executed: printAOPName
Target where the advice is applied on: in.sblog.spring.aop.service.AOPService@c980c9
AOPARoundMethod.invoke() overrides MethodInterceptor.invoke()
Method which gets executed: printAOPName
Before Method executing
inside AOPService::printAOPName.
AOP Id:1000, AOP Name: sblog.in
After Method executing
AOPAfterReturningMethod.afterReturning() overrides AfterReturningAdvice.afterReturning()
Method which returns: null
Method which gets executed: printAOPName
Target where the advice is applied on: in.sblog.spring.aop.service.AOPService@c980c9
--------------------------------------------
--------------------------------------------
AOPBeforeMethod.before() overrides MethodBeforeAdvice.before()
Method which gets executed: isValidNameLength
Target where the advice is applied on: in.sblog.spring.aop.service.AOPService@c980c9
AOPARoundMethod.invoke() overrides MethodInterceptor.invoke()
Method which gets executed: isValidNameLength
Before Method executing
Name is valid!
After Method executing
AOPAfterReturningMethod.afterReturning() overrides AfterReturningAdvice.afterReturning()
Method which returns: null
Method which gets executed: isValidNameLength
Target where the advice is applied on: in.sblog.spring.aop.service.AOPService@c980c9
--------------------------------------------
--------------------------------------------
AOPBeforeMethod.before() overrides MethodBeforeAdvice.before()
Method which gets executed: printAnyMessage
Arguments passed to the method:
args[0]: from www.sblog.in tutorial
Target where the advice is applied on: in.sblog.spring.aop.service.AOPService@c980c9
AOPARoundMethod.invoke() overrides MethodInterceptor.invoke()
Method which gets executed: printAnyMessage
Arguments passed to the method:
args[0]: from www.sblog.in tutorial
Before Method executing
Message: from www.sblog.in tutorial
After Method executing
AOPAfterReturningMethod.afterReturning() overrides AfterReturningAdvice.afterReturning()
Method which returns: null
Method which gets executed: printAnyMessage
Arguments passed to the method:
args[0]: from www.sblog.in tutorial
Target where the advice is applied on: in.sblog.spring.aop.service.AOPService@c980c9
--------------------------------------------

 
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 one that matches a method by its name and the one that matches a method using a regular expression pattern. Let’s see how both types of Pointcuts can be used.

Pointcut matching a name

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 aopContext.xml. In its property mappedName, the value to be set is the name of the method that will be intercepted. Here, we will intercept printAnyMessage(String msg) method.

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

Finally, in aopServiceProxy bean we must replace the AOPARoundMethod value of interceptorNames property with the aopServiceBean.

<?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: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="aopServiceBean" class="in.sblog.spring.aop.service.AOPService">
        <property name="aopId" value="1000"></property>
        <property name="aopName" value="sblog.in"></property>
    </bean><bean id="aopAOPAroundMethodBean" class="in.sblog.spring.aop.advice.AOPARoundMethod"></bean><bean id="aopPointcut" class="org.springframework.aop.support.NameMatchMethodPointcut">
        <property name="mappedName" value="printAnyMessage"></property>
    </bean><bean id="aopAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
        <property name="pointcut" ref="aopPointcut"></property>
        <property name="advice" ref="aopAOPAroundMethodBean"></property>
    </bean><bean id="aopServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="aopServiceBean"></property>
        <property name="interceptorNames">
            <list>
                <value>aopAdvisor</value>
            </list>
        </property>
    </bean>
</beans>

 

We run the TestAOP.java again. Now, only the printAnyMessage(String msg) method is being intercepted.

Output:

--------------------------------------------
inside AOPService::printAOPName.
AOP Id:1000, AOP Name: sblog.in
--------------------------------------------
--------------------------------------------
Name is valid!
--------------------------------------------
--------------------------------------------
AOPARoundMethod.invoke() overrides MethodInterceptor.invoke()
Method which gets executed: printAnyMessage
Arguments passed to the method:
args[0]: from www.sblog.in tutorial
Before Method executing
Message: from www.sblog.in tutorial
After Method executing
--------------------------------------------

 

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

<?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: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="aopServiceBean" class="in.sblog.spring.aop.service.AOPService">
        <property name="aopId" value="1000"></property>
        <property name="aopName" value="sblog.in"></property>
    </bean><bean id="aopAOPAroundMethodBean" class="in.sblog.spring.aop.advice.AOPARoundMethod"></bean><bean id="aopAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
        <property name="mappedName" value="printAnyMessage"></property>
        <property name="advice" ref="aopAOPAroundMethodBean"></property>
    </bean><bean id="aopServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="aopServiceBean"></property>
        <property name="interceptorNames">
            <list>
                <value>aopAdvisor</value>
            </list>
        </property>
    </bean>
</beans>

 
Output:

--------------------------------------------
inside AOPService::printAOPName.
AOP Id:1000, AOP Name: sblog.in
--------------------------------------------
--------------------------------------------
Name is valid!
--------------------------------------------
--------------------------------------------
AOPARoundMethod.invoke() overrides MethodInterceptor.invoke()
Method which gets executed: printAnyMessage
Arguments passed to the method:
args[0]: from www.sblog.in tutorial
Before Method executing
Message: from www.sblog.in tutorial
After Method executing
--------------------------------------------

 
Pointcut matching a regex

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 *sblog* pattern, so again the printAnyMessage(String msg) method will be intercepted. The advice property holds a reference to the bean of the advice.

<?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: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="aopServiceBean" class="in.sblog.spring.aop.service.AOPService">
        <property name="aopId" value="1000"></property>
        <property name="aopName" value="sblog.in"></property>
    </bean><bean id="aopAOPAroundMethodBean" class="in.sblog.spring.aop.advice.AOPARoundMethod"></bean><bean id="aopAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <property name="patterns">
            <list>
                <value>.*sblog.*</value>
            </list>
        </property>
        <property name="advice" ref="aopAOPAroundMethodBean"></property>
    </bean><bean id="aopServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="aopServiceBean"></property>
        <property name="interceptorNames">
            <list>
                <value>aopAdvisor</value>
            </list>
        </property>
    </bean>
</beans>

 

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

Output:

--------------------------------------------
AOPARoundMethod.invoke() overrides MethodInterceptor.invoke()
Method which gets executed: printAOPName
Before Method executing
inside AOPService::printAOPName.
AOP Id:1000, AOP Name: sblog.in
After Method executing
--------------------------------------------
--------------------------------------------
AOPARoundMethod.invoke() overrides MethodInterceptor.invoke()
Method which gets executed: isValidNameLength
Before Method executing
Name is valid!
After Method executing
--------------------------------------------
--------------------------------------------
AOPARoundMethod.invoke() overrides MethodInterceptor.invoke()
Method which gets executed: printAnyMessage
Arguments passed to the method:
args[0]: from www.sblog.in tutorial
Before Method executing
Message: from www.sblog.in tutorial
After Method executing
--------------------------------------------

 
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 need to create a new Around method advice, AOPARoundMethod.java class and add it to aopContext.xml as shown below:

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class AOPARoundMethod2 implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out
                .println("AOPARoundMethod2.invoke() overrides MethodInterceptor.invoke()");
        System.out.println("Method which gets executed: "
                + methodInvocation.getMethod().getName());
        if (methodInvocation.getArguments().length > 0) {
            System.out.println("Arguments passed to the method:");
            for (int i = 0; i < methodInvocation.getArguments().length; i++) {
                System.out.println("args[" + i + "]: "
                        + methodInvocation.getArguments()[i]);
            }
        }
        System.out.println("Before Method executing");
        try {
            Object result = methodInvocation.proceed();
            System.out.println("After Method executing");
            return result;
        } catch (Throwable t) {
            System.out.println("When Exceptions are thrown");
            throw t;
        }
    }
}

 

<?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: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="aopServiceBean" class="in.sblog.spring.aop.service.AOPService">
        <property name="aopId" value="1000"></property>
        <property name="aopName" value="sblog.in"></property>
    </bean><bean id="aopAOPAroundMethodBean" class="in.sblog.spring.aop.advice.AOPARoundMethod"></bean><bean id="aopAOPAroundMethodBean2" class="in.sblog.spring.aop.advice.AOPARoundMethod2"></bean><bean id="aopServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="aopServiceBean"></property>
        <property name="interceptorNames">
            <list>
                <value>aopAOPAroundMethodBean</value>
                <value>aopAOPAroundMethodBean2</value>
            </list>
        </property>
    </bean>
</beans>

 

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

Output:

--------------------------------------------
AOPARoundMethod.invoke() overrides MethodInterceptor.invoke()
Method which gets executed: printAOPName
Before Method executing
AOPARoundMethod2.invoke() overrides MethodInterceptor.invoke()
Method which gets executed: printAOPName
Before Method executing
inside AOPService::printAOPName.
AOP Id:1000, AOP Name: sblog.in
After Method executing
After Method executing
--------------------------------------------
--------------------------------------------
AOPARoundMethod.invoke() overrides MethodInterceptor.invoke()
Method which gets executed: isValidNameLength
Before Method executing
AOPARoundMethod2.invoke() overrides MethodInterceptor.invoke()
Method which gets executed: isValidNameLength
Before Method executing
Name is valid!
After Method executing
After Method executing
--------------------------------------------
--------------------------------------------
AOPARoundMethod.invoke() overrides MethodInterceptor.invoke()
Method which gets executed: printAnyMessage
Arguments passed to the method:
args[0]: from www.sblog.in tutorial
Before Method executing
AOPARoundMethod2.invoke() overrides MethodInterceptor.invoke()
Method which gets executed: printAnyMessage
Arguments passed to the method:
args[0]: from www.sblog.in tutorial
Before Method executing
Message: from www.sblog.in tutorial
After Method executing
After Method executing
--------------------------------------------

 

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

<?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: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="aopServiceBean" class="in.sblog.spring.aop.service.AOPService">
        <property name="aopId" value="1000"></property>
        <property name="aopName" value="sblog.in"></property>
    </bean><bean id="aopAOPAroundMethodBean" class="in.sblog.spring.aop.advice.AOPARoundMethod"></bean><bean id="aopAOPAroundMethodBean2" class="in.sblog.spring.aop.advice.AOPARoundMethod2"></bean><bean id="aopServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="aopServiceBean"></property>
        <property name="interceptorNames">
            <list>
                <value>aopAOPAroundMethodBean2</value>
                <value>aopAOPAroundMethodBean</value>
            </list>
        </property>
    </bean>
</beans>

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

--------------------------------------------
AOPARoundMethod2.invoke() overrides MethodInterceptor.invoke()
Method which gets executed: printAOPName
Before Method executing
AOPARoundMethod.invoke() overrides MethodInterceptor.invoke()
Method which gets executed: printAOPName
Before Method executing
inside AOPService::printAOPName.
AOP Id:1000, AOP Name: sblog.in
After Method executing
After Method executing
--------------------------------------------
--------------------------------------------
AOPARoundMethod2.invoke() overrides MethodInterceptor.invoke()
Method which gets executed: isValidNameLength
Before Method executing
AOPARoundMethod.invoke() overrides MethodInterceptor.invoke()
Method which gets executed: isValidNameLength
Before Method executing
Name is valid!
After Method executing
After Method executing
--------------------------------------------
--------------------------------------------
AOPARoundMethod2.invoke() overrides MethodInterceptor.invoke()
Method which gets executed: printAnyMessage
Arguments passed to the method:
args[0]: from www.sblog.in tutorial
Before Method executing
AOPARoundMethod.invoke() overrides MethodInterceptor.invoke()
Method which gets executed: printAnyMessage
Arguments passed to the method:
args[0]: from www.sblog.in tutorial
Before Method executing
Message: from www.sblog.in tutorial
After Method executing
After Method executing
--------------------------------------------

 
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.

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 aopContext.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.

<?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: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="aopServiceBean" class="in.sblog.spring.aop.service.AOPService">
        <property name="aopId" value="1000"></property>
        <property name="aopName" value="sblog.in"></property>
    </bean><bean id="aopAOPAroundMethodBean" class="in.sblog.spring.aop.advice.AOPARoundMethod"></bean><bean id="aopPointcut" class="org.springframework.aop.support.NameMatchMethodPointcut">
        <property name="mappedName" value="printAnyMessage"></property>
    </bean><bean id="aopAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
        <property name="mappedName" value="printAnyMessage"></property>
        <property name="advice" ref="aopAOPAroundMethodBean"></property>
    </bean><bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        <property name="beanNames">
            <list>
                <value>*ServiceBean</value>
            </list>
        </property>
        <property name="interceptorNames">
            <list>
                <value>aopAdvisor</value>
            </list>
        </property>
    </bean>
</beans>

 

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

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestAOP {
    public static void main(String[] args) {
        @SuppressWarnings("resource")
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
                "aopContext.xml");
        AOPService aopService = (AOPService) applicationContext
                .getBean("aopServiceBean");
        System.out.println("--------------------------------------------");
        aopService.printAOPName();
        System.out.println("--------------------------------------------");
        System.out.println();
        System.out.println("--------------------------------------------");
        aopService.isValidNameLength();
        System.out.println("--------------------------------------------");
        System.out.println();
        System.out.println("--------------------------------------------");
        aopService.printAnyMessage("from www.sblog.in tutorial");
        System.out.println("--------------------------------------------");
    }
}

 
Output:

--------------------------------------------
inside AOPService::printAOPName.
AOP Id:1000, AOP Name: sblog.in
--------------------------------------------
--------------------------------------------
Name is valid!
--------------------------------------------
--------------------------------------------
AOPARoundMethod.invoke() overrides MethodInterceptor.invoke()
Method which gets executed: printAnyMessage
Arguments passed to the method:
args[0]: from www.sblog.in tutorial
Before Method executing
Message: from www.sblog.in tutorial
After Method executing
--------------------------------------------

 
DefaultAdvisorAutoProxyCreator

The second auto proxy creator Spring provides is the DefaultAdvisorAutoProxyCreator that automatically applies advisors in the current aopContext.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 aopContext.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.

<?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: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="aopServiceBean" class="in.sblog.spring.aop.service.AOPService">
        <property name="aopId" value="1000"></property>
        <property name="aopName" value="sblog.in"></property>
    </bean><bean id="aopPointcut" class="org.springframework.aop.support.NameMatchMethodPointcut">
        <property name="mappedName" value="printAnyMessage"></property>
    </bean><bean id="aopAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
        <property name="mappedName" value="printAnyMessage"></property>
        <property name="advice" ref="aopAOPAroundMethodBean"></property>
    </bean><bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>
</beans>

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

--------------------------------------------
inside AOPService::printAOPName.
AOP Id:1000, AOP Name: sblog.in
--------------------------------------------
--------------------------------------------
Name is valid!
--------------------------------------------
--------------------------------------------
AOPARoundMethod.invoke() overrides MethodInterceptor.invoke()
Method which gets executed: printAnyMessage
Arguments passed to the method:
args[0]: from www.sblog.in tutorial
Before Method executing
Message: from www.sblog.in tutorial
After Method executing
--------------------------------------------

 
Thanks for your reading. Please do not forget to leave a comment.

Leave a Reply

Your email address will not be published. Required fields are marked *