Spring AOP Before Advice Annotation Example

0

In this article, we will use AspectJ annotation support in Spring to write a before advice.

A before advice handles the crosscutting concerns before the execution point of a program.

This example uses the following frameworks:

  1. Maven 3.2.3
  2. Spring 4.2.0.RELEASE
  3. Eclipse  as the IDE, version Luna 4.4.1.

Dependencies

To use AspectJ annotations in your Spring application, you have to include the appropriate dependencies in your classpath. If you are using Maven, add the following declarations to your Maven project’s pom.xml.

pom.xml:

<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/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.javarticles.jdbc.datasource</groupId>
	<artifactId>springdatasource</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>1.8.6</version>
		</dependency>
	</dependencies>

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

</project>

Simple Test Bean

Our test bean contains few simple methods with print statements.

TestBean:

package com.javarticles;

public class TestBean {
    public void methodA() {
        System.out.println("'void methodA()' called");
    }
    
    public void methodA(String a, String b) {
        System.out.println("'void methodA(" + a + ", " + b + ")' called");
    }
    
    public String methodA(String a) {
        System.out.println("'String methodA(" + a + ")' called");
        return a;
    }
    
    public String methodB(String a, String b) {
        System.out.println("'String methodB(" + a +", " + b + ")' called");
        return a + b;
    }
}

We register the bean in spring XML.

applicationContxt.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: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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

	<bean id="testBean" class="com.javarticles.TestBean"/>	
</beans>

Let’s call the test bean methods. We will do the same exercise again but with Aspects intercepting the method call.

SpringAppContextExample:

package com.javarticles;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringAppContextExample {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
                "applicationContext.xml");
        try {
            TestBean testBean = (TestBean) context.getBean("testBean");
            System.out.println("Call testBean.methodA()");
            testBean.methodA();
            
            System.out.println("Call testBean.methodA('one', 'two')");
            testBean.methodA("one", "two");
            
            System.out.println("Call testBean.methodB('one', 'two')");
            testBean.methodB("one", "two");
        } finally {
            context.close();
        }
    }
}

Output:

Call testBean.methodA()
'void methodA()' called
Call testBean.methodA('one', 'two')
'void methodA(one, two)' called
Call testBean.methodB('one', 'two')
'String methodB(one, two)' called

AspectJ Annotations

Using AspectJ Annotations, we can now annotate any POJO classes and turn them into aspects. In order for the spring to treat them as Aspects, we must declare an autoproxy bean in the Spring context that knows how to turn @AspectJ-annotated beans into proxy advice. To enable AsepectJ annotation support in spring, we need to include spring defined empty XML element <aop:aspectj-autoproxy> in the spring configuration XML file. When spring comes across this element, it automatically creates proxies for any bean annotated with @AspectJ annotations.

Internally, spring creates AspectJAwareAdvisorAutoProxyCreator subclass that processes all AspectJ annotation aspects in the current application context, as well as Spring Advisors. Any POJO class with @Aspect annotation is considered as AspectJ aspect suitable for use by the Spring AOP system.

applicationContext.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: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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

	<bean id="testBean" class="com.javarticles.TestBean"/>
	
        <aop:aspectj-autoproxy/>

</beans>

<aop:aspectj-autoproxy/> scans for beans annotated with @Aspect and then looks for Spring AOP Advisors for AspectJ methods annotated with any one of the below annotations.

  1. @Before
  2. @Around
  3. @After
  4. @AfterReturning
  5. @AfterThrowing

AopBean is a simple bean annotated with AspectJ annotations. In this example, we will create a @Before advice. Based on the pointcut expressions, spring figures out the methods on which it needs to apply the before advice. The expression is provided as annotation value.

Let’s go through each expression.

  1. @Before(“execution(void methodA())”) – Applies on methods with signature void methodA()
  2. @Before(“execution(void methodA(String, String))”) – Applies on methods with signature void methodA(String, String)
  3. @Before(value=”execution(* methodA(String, String)) and args(a, b)”, argNames=”a,b”) – Applies on methods with signature * methodA(String, String). The preceding wildcard ‘*’ in this expression matches any modifier (public, protected, and
    private) and any return type. The arguments of the method on which the advisor is applied are mapped to ‘a’ and b’ arguments of the advisor method.

    public void beforeMethodA3(String a, String b) {
            System.out.println("@Before AOP, execution point: 'void methodA(" + a + ", " + b + ")'");
        }
  4. @Before(value=”execution(* method*(String, String)) and args(a, b)”, argNames=”a,b”) – You will ‘*’ in return value place as well as the method name which means it gets applied on any method that starts with ‘method’.

If you want the advisor to get applied on a method with any number of arguments then you need to use two dots in the argument list which means match any number of arguments.
@Before(value=”execution(* methodA(String, String)) and args(a, b)”, argNames=”a,b”)

AopBean:

package com.javarticles;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class AopBean {
    @Before("execution(void methodA())")    
    public void beforeMethodA1() {
        System.out.println("@Before AOP, execution point: 'void methodA()'");
    }
    
    @Before("execution(void methodA(String, String))")    
    public void beforeMethodA2() {
        System.out.println("@Before AOP, execution point: 'void methodA(String, String)'");
    }
    
    @Before(value="execution(* methodA(String, String)) and args(a, b)", argNames="a,b")    
    public void beforeMethodA3(String a, String b) {
        System.out.println("@Before AOP, execution point: 'void methodA(" + a + ", " + b + ")'");
    }    
    
    @Before(value="execution(* method*(String, String)) and args(a, b)", argNames="a,b")    
    public void beforeAnyMethod(String a, String b) {
        System.out.println("@Before AOP, execution point: 'void method*(" + a + ", " + b + ")'");
    }   
}

We need to register AopBean applicationContext.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: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/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

	<bean id="testBean" class="com.javarticles.TestBean"/>
	
        <aop:aspectj-autoproxy/>
	<bean id="aopBean" class="com.javarticles.AopBean"/>
</beans>

SpringAppContextExample:

package com.javarticles;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringAppContextExample {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
                "applicationContext.xml");
        try {
            TestBean testBean = (TestBean) context.getBean("testBean");
            System.out.println("Call testBean.methodA()");
            testBean.methodA();
            
            System.out.println("Call testBean.methodA('one', 'two')");
            testBean.methodA("one", "two");
            
            System.out.println("Call testBean.methodB('one', 'two')");
            testBean.methodB("one", "two");
        } finally {
            context.close();
        }
    }
}

Output:

Call testBean.methodA()
@Before AOP, execution point: 'void methodA()'
'void methodA()' called
Call testBean.methodA('one', 'two')
@Before AOP, execution point: 'void method*(one, two)'
@Before AOP, execution point: 'void methodA(String, String)'
@Before AOP, execution point: 'void methodA(one, two)'
'void methodA(one, two)' called
Call testBean.methodB('one', 'two')
@Before AOP, execution point: 'void method*(one, two)'
'String methodB(one, two)' called

Download source code

This was an example about Spring AOP Before Advice Annotation.

You can download the source code here: springAopBeforeAdviceAnnotationExample.zip
Share.

Comments are closed.