Friday, February 19, 2010

Spring AOP with @AspectJ annotations

Here's a quick sample on how to use Spring's AOP feature with @AspectJ annotations.  First off, please read the Spring Reference manual on AOP.  This post is a copy and paste tutorial (hopefully I get it right :P).  We begin by creating a normal Java Project in Eclipse.  I've named it "springtest".  You can name it whatever you like.  Here's a screenshot of the project in Eclipse:

Take note of the JAR files in the project.  Those are the JAR files required by Spring to use AOP features.  They can be found in Spring's lib and dist folders (you'll need the full Spring download with dependencies).
  • spring.jar - main Spring JAR file; obtained from the "dist" folder
  • aspectjrt.jar, aspjectjweaver.jar - AspectJ JAR file; obtained from "lib/aspectj" folder
  • commons-logging.jar - Commons logging JAR file; obtained from "lib/jakarta-commons" folder
  • cglib-nodep-2.1_3.jar - Code generation lib JAR file; obtained from "lib/cglib" folder

Spring Application Context File - app-ctx.xml
Create the Spring app context file in the com.aop package and name it app-ctx.xml.  Here's the contents of the file:

<?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: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-2.5.xsd">

    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
   
    <bean id="myBean" class="com.aop.MyBean"/>
   
    <bean id="myAspect" class="com.aop.MyAspect"/>
</beans>

The highlighted line is to enable @AspectJ autoproxying of beans declared. 


Aspect Class - MyAspect.java
Next, create a Java class file and name it MyAspect.java.  This file will contain the Aspect as well as the PointCut we'll be using for this simple how to.  File content shown below:

package com.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class MyAspect {
   
    @Around("execution(public * *(..))")
    public Object executor(ProceedingJoinPoint point) throws Throwable {

        System.out.println("Cutting before...");
       
        Object retVal = point.proceed();
       
        if (retVal != null) {
            System.out.println("returned object: " + retVal.toString());
        }
       
        System.out.println("Cutting after...");
       
        return retVal;
    }
}
Remember that aspectj-autoproxy declaration in the app-ctx.xml file?  Once we annotate a class file using the @Aspect, Spring AOP will automatically pickup and process the class files.

Notice that we're using the Around advice.  What this does is prints the line "Cutting before..." right before the method is executed and "Cutting after..." right after the method is executed.  If the method returns a value, print it out.  For more information on other types of advices, please refer to the Spring reference doc :)  What we're doing here is to cut around all public methods. 


The Simple Spring Managed Bean - MyBean.java
This is a simple Spring managed bean which contains methods which will be intercepted by the aspect class defined above.  Here's the file contents:

package com.aop;

public class MyBean {
    public void test() {
        System.out.println("MyBean>>>test");
    }
   
    public void test2() {
        System.out.println("MyBean>>>test2");
    }
   
    public String returnTest() {
        System.out.println("MyBean>>>returnTest");
        return "this is a test";
    }
}

The Main class - MainRunner.java
This will be the class which contains the main method.  Here's the contents:

package com.aop;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainRunner {
    public static void main(String[] args) {
        try {
            ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("com/aop/app-ctx.xml");
           
            MyBean bean = (MyBean) ctx.getBean("myBean");
            bean.test();
            bean.test2();
            bean.returnTest();
           
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
   
}
The first step is to obtain the application context via ClassPathXmlApplicationContext.  Then call get an instance of MyBean and subsequently call its methods (test, test2 and returnTest).  If you've done everything right, run the program and the following output should be displayed:

Cutting before...
MyBean>>>test
Cutting after...
Cutting before...
MyBean>>>test2
Cutting after...
Cutting before...
MyBean>>>returnTest
returned object: this is a test
Cutting after...
There you have it, the simplest way of AOP :)

No comments: