Computing Magazine

Spring Aop (Part 1)

Posted on the 14 May 2013 by Skiabox @skiabox
Spring Aop (Part 1)

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 :

Spring Aop (Part 1)

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):

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>foo.bar</groupId>
    <artifactId>SimpleSpring18</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>SimpleSpring18</name>
    <url>http://maven.apache.org</url>

    <properties>
        <spring.version>3.2.2.RELEASE</spring.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.8.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.2</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.7.2</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.7.2</version>
        </dependency>
    </dependencies>

    <build>
        <finalName>SpringApp</finalName>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>
                    <includes>
                        <include>**/*Tests.java</include>
                    </includes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

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:

<?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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <context:annotation-config />
    <context:component-scan base-package="foo.bar"/>

    <bean id="myDependency" class="foo.bar.MyDependency"/>

    <bean id="myBean" class="foo.bar.MyBean">
        <property name="dep" ref="myDependency"/>
    </bean>
</beans>

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):

<?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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <context:annotation-config />
    <context:component-scan base-package="foo.bar"/>

    <bean id="advice" class="foo.bar.MyAdvice"/>

    <bean id="myDependency" class="foo.bar.MyDependency"/>

    <bean id="myBean" class="foo.bar.MyBean">
        <property name="dep" ref="myDependency"/>
    </bean>
</beans>

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):

<?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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <context:annotation-config />
    <context:component-scan base-package="foo.bar"/>

    <aop:config>
        <aop:pointcut id="fooExecution" expression="execution(* foo*(int))"/>
        <aop:aspect ref="advice">
            <aop:before method="simpleBeforeAdvice" pointcut-ref="fooExecution"/>
        </aop:aspect>
    </aop:config>

    <bean id="advice" class="foo.bar.MyAdvice"/>

    <bean id="myDependency" class="foo.bar.MyDependency"/>

    <bean id="myBean" class="foo.bar.MyBean">
        <property name="dep" ref="myDependency"/>
    </bean>
</beans>

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
Spring Aop (Part 1)

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):

Project2 Result
Spring Aop (Part 1)
<?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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <context:annotation-config />
    <context:component-scan base-package="foo.bar"/>

    <aop:config>
        <aop:pointcut id="fooExecution" expression="execution(* foo*(int)) and args(intValue) and bean(myDependency*)"/>
        <aop:aspect ref="advice">
            <aop:before pointcut-ref="fooExecution" method="simpleBeforeAdvice"/>
        </aop:aspect>
    </aop:config>

    <bean id="advice" class="foo.bar.MyAdvice"/>

    <bean id="myDependency" class="foo.bar.MyDependency"/>

    <bean id="myBean" class="foo.bar.MyBean">
        <property name="dep" ref="myDependency"/>
    </bean>
</beans>

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.


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;
    }
}
Project3 Result
Spring Aop (Part 1)

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):

<?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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <context:annotation-config />
    <context:component-scan base-package="foo.bar"/>

    <aop:config>
        <aop:pointcut id="fooExecution" expression="execution(* foo*(int)) and args(intValue) and bean(myDependency*)"/>

        <aop:aspect ref="advice">
            <aop:before pointcut-ref="fooExecution" method="simpleBeforeAdvice"/>
            <aop:around pointcut-ref="fooExecution" method="simpleAroundAdvice"/>
        </aop:aspect>
    </aop:config>

    <bean id="advice" class="foo.bar.MyAdvice"/>

    <bean id="myDependency" class="foo.bar.MyDependency"/>

    <bean id="myBean" class="foo.bar.MyBean">
        <property name="dep" ref="myDependency"/>
    </bean>
</beans>


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


Back to Featured Articles on Logo Paperblog

Magazines