Computing Magazine

Spring Aop (Part 1)

Posted on the 14 May 2013 by Skiabox @skiabox

Spring is an open source application framework and IoC (inversion of control) container for the Java platform.
More details and a detailed explanation of IoC or Dependency Injection (as IT community decided to call it) can be found in this article by Martin Fowler.

In this article I want to talk about how spring uses AOP (Aspect-oriented programming) to inject cross-cutting code (before, after or around existing methods) to a spring project.
The ide I am using is IntelliJ IDEA Ultimate 12.

We will create 3 projects in this tutorial.
In the first project , I will show you how to inject code before an existing method.
So let’s start.

We go to File –> New Project and we name our project as ‘SimpleSpring1′ like this :

Image1

Don’t forget to add the following two AspectJ maven dependencies (apsectjrt and aspectjweaver), because we are using AspectJ in our projects.
Check this link for more information about AspectJ and the terminology we use in this article (pointcuts, join points, advice).
Here is my pom.xml file after I added the two needed dependencies (highlighted code):

    4.0.0
    foo.bar
    SimpleSpring18
    jar
    1.0-SNAPSHOT
    SimpleSpring18
    http://maven.apache.org

    
        3.2.2.RELEASE
    

    
        
            org.springframework
            spring-core
            ${spring.version}
        

        
            org.springframework
            spring-context
            ${spring.version}
        

        
            junit
            junit
            4.8.2
            test
        
        
            org.springframework
            spring-test
            ${spring.version}
            test
        
        
            org.slf4j
            slf4j-log4j12
            1.7.2
        

        
            org.aspectj
            aspectjrt
            1.7.2
        
        
            org.aspectj
            aspectjweaver
            1.7.2
        
    

    
        SpringApp
        
            
                maven-compiler-plugin
                
                    1.6
                    1.6
                
            
            
                maven-surefire-plugin
                
                    
                        **/*Tests.java
                    
                
            
        
    

Next we create MyBean class and we inject to it a dependency class called MyDependency using setter injection.

MyBean.java :

package foo.bar;

public class MyBean {

    private MyDependency dep;

    public void setDep(MyDependency dep) {
        this.dep = dep;
    }

    //other methods
    public void execute()
    {
        dep.foo(10);
        dep.foo(11);
        dep.bar();
    }
}

MyDependency.java:

package foo.bar;

public class MyDependency {

    public void foo(int intValue)
    {
        System.out.println("foo(int): " + intValue);
    }

    public void bar()
    {
        System.out.println("bar()");
    }
}

The next step is to declare these two beans in our spring-config.xml (this file is automatically created by IntelliJ Idea and it is placed inside resources folder).

spring-config.xml:

    
    

    

    
        
    

Now using AOP terms, we’ll create an ‘advice’, which means that extra code that we inject before, after or around an existing method using AspectJ joinpoints.
So we write a MyAdvice class like this.
MyAdvice.java:

package foo.bar;

import org.aspectj.lang.JoinPoint;

public class MyAdvice {

    public void simpleBeforeAdvice(JoinPoint joinPoint)
    {
        System.out.println("Executing: " + joinPoint.getSignature().getDeclaringTypeName() + " " + joinPoint.getSignature().getName());
    }
}

I believe that getDeclaringTypeName() and getName() functions are self-descriptive, as the first return the existing method type we target and the second one returns its name.
As with any other bean we use in our application, we must declare MyAdvice class into spring-config.xml

spring-config.xml(updated):

    
    

    

    

    
        
    

The final step is to declare an aop:config tag in our spring-config.xml configuration file.
Here is the tag we must add.
spring-config.xml(updated):

    
    

    
        
        
            
        
    

    

    

    
        
    

Using the the pointcut tag we choose the methods that we want to target for the current package.
The first asterisk that you see in the pointcut expression attribute (just after execution keyword) is the return type (any), foo* targets all methods that start with foo, and of course int means ‘one argument of integer type’.
For more information about AspectJ check this AspectJ cheat sheet that uses @AspectJ-Style Annotations (we’ll talk about this annotation style in my next article-Spring Aop Part2)
In the aspect tag we reference the advice bean using ref keyword, and inside it we use before tag to declare the advice method and referencing the already declared pointcut using pointcut-ref tag attribute.

Now all that remains is to create an application entry point that starts the application.
StartingPoint.java:

package foo.bar;

import org.springframework.context.support.GenericXmlApplicationContext;

public class StartingPoint {

    public static void main(String[] args) {
        GenericXmlApplicationContext ctx = new GenericXmlApplicationContext("spring-config.xml");

        MyBean myBean = (MyBean)ctx.getBean("myBean");
        myBean.execute();
    }
}

This is a classic Spring Container startup.
First we create the context object and then using this object(ctx) we ask the spring container to instantiate for us MyBean.
The manual casting to the MyBean type is necessary because ctx.getBean() method returns an Object type.
Running our application we get the following result :

Project1 Result

Project1

As you see the before advice is working as it should work, and it appears just before the target method execution.
Now for the second project we will create the same base project, but now we want to add an advice before our existing foo method only when an integer argument of foo is not equal to 10 and only when the bean ID starts with myDependency.
So we alter our MyAdvice class, and now it looks like this.
MyAdvice.java(updated):

package foo.bar;

import org.aspectj.lang.JoinPoint;

public class MyAdvice {

    //For both joinpoint and argument retrieval
    public void simpleBeforeAdvice(JoinPoint joinPoint, int intValue)
    {
        //Execute only when intValue is not 10
        if (intValue != 10)
        {
            System.out.println("Executing: " + joinPoint.getSignature().getDeclaringTypeName() + " " + joinPoint.getSignature().getName()
            + " argument: " + intValue);
        }
    }
}

That is the code for the new MyAdvice class, but we’re not finished yet, as we must also modify the expression attribute of our pointcut inside the spring-config.xml
Here is the code of the complete spring-config.xml configuration file, with the updated lines highlighted.

spring-config.xml(updated):

    
    

    
        
        
            
        
    

    

    

    
        
    

With the args directive we pass the intValue argument of our foo directive into the before advice.
The second directive(bean) instructs Spring to advice only the beans that their id starts with myDependency.
So let’s run our StartingPoint entry class to see what we get.

Project2 Result

Project2


As the last project, we’ll see how we can add an around advice.
The points that we need to alter this time (since our base application remains the same) are again the same two (MyAdvice class and aop:config tag in spring-config.xml)
So let’s change MyAdvice class by adding a simpleAroundAdvice (which takes at least one argument of type ProceedingJoinPoint) and keep the intValue again as a second argument, so that we can use it in this new advice.

MyAdvice.java(updated):

package foo.bar;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

public class MyAdvice {

    //For both joinpoint and argument retrieval
    public void simpleBeforeAdvice(JoinPoint joinPoint, int intValue)
    {
        //Execute only when intValue is not 10
        if (intValue != 10)
        {
            System.out.println("Executing: " + joinPoint.getSignature().getDeclaringTypeName() + " " + joinPoint.getSignature().getName()
                    + " argument: " + intValue);
        }
    }

    public Object simpleAroundAdvice(ProceedingJoinPoint pjp, int intValue) throws Throwable
    {
        System.out.println("Before execution: " + pjp.getSignature().getDeclaringTypeName() + " " + pjp.getSignature().getName()
            + " argument: " + intValue);

        Object retVal = pjp.proceed();

        System.out.println("After execution: " + pjp.getSignature().getDeclaringTypeName() + " " + pjp.getSignature().getName()
                + " argument: " + intValue);

        return retVal;
    }
}

The key line in our new method is the one with the proceed() function that tells the system to proceed after the before advice.
For the spring xml configuration we just add an aop:around tag inside our aop:aspect tag like this :

spring-config.xml(updated):

    
    

    
        

        
            
            
        
    

    

    

    
        
    


Now if we run again, for the last time, our StartingPoint class we get the following result.

Project3 Result

Project3


Back to Featured Articles on Logo Paperblog