Spring Tutorial - Spring AOP








Besides Dependency Injection (DI), another core feature that the Spring Framework offers is aspect-oriented programming (AOP).

AOP is a tool for implementing crosscutting concerns.

The crosscutting concerns refers to logic in an application that cannot be decomposed from the rest of the application and may result in code duplication and tight coupling.

AOP is a programming paradigm that aims to increase modularity by allowing the separation of cross-cutting concerns.

Adding Log methods to every single method is a cross-cutting concern. A logging strategy affects every logged part of the system. The log methods would cross-cut all logged classes and methods.

Spring AOP framework modularizes cross-cutting concerns in aspects. When executing a method in Spring IoC container, Spring AOP can hijack the executing method, and add extra functionality before or after the method execution.





AOP Concepts

AOP comes with its own specific set of concepts and terms.

The following are the core concepts of AOP:

  • Joinpoints is a point during the execution of your application. Typical example of joinpoints is a call to a method. Joinpoints define the points in your application at which you can insert additional logic using AOP.
  • Advice is the code executed at a particular joinpoint. There are many types of advice, such as before , which executes before the joinpoint, and after , which executes after it.
  • Pointcut is a collection of joinpoints that is used to define when advice should be executed. By creating pointcuts, we control over how to apply advice to the Java Bean in the application.
  • Weaving is the process of inserting aspects into the application code at the appropriate point.
  • An object whose execution flow is modified by an AOP process is referred to as the target object or advised object.

Spring AOP has four type of advices.

  • Before advice - Run before the method execution
  • After returning advice - Run after the method returns a result
  • After throwing advice - Run after the method throws an exception
  • Around advice - Run around the method execution, combine all three advices above.

Advice is an action to take either before or after the method execution.





dependency

Add the following new dependency for AOP coding to POM.xml.

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.2.2</version>
</dependency>

Java Bean

The following code defines a Java bean for a printer service.

package com.java2s.common;

public class PrinterService {
  private String name;
  private String url;
  public void setName(String name) {
    this.name = name;
  }
  public void setUrl(String url) {
    this.url = url;
  }
  public void printName() {
    System.out.println("Printer Name : " + this.name);
  }
  public void printURL() {
    System.out.println("Printer URL : " + this.url);
  }
  public void printThrowException() {
    throw new IllegalArgumentException();
  }
}

XML configuration

Here is the Spring-Customer.xml file for bean configuration.

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
  <bean id="myService" class="com.java2s.common.PrinterService">
    <property name="name" value="printerName" />
    <property name="url" value="http://www.java2s.com" />
  </bean>
</beans>

The following is the main class to run the code above.

package com.java2s.common;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
  public static void main(String[] args) {
    ApplicationContext appContext = new ClassPathXmlApplicationContext(
        new String[] { "SpringBeans.xml" });
    PrinterService cust = (PrinterService) appContext.getBean("myService");
    cust.printName();
    cust.printURL();
    try {
      cust.printThrowException();
    } catch (Exception e) {
    }
  }
}

Output



Download Java2s_Spring_Pre_AOP.zip

Before advice

The following code shows how to add Before advice.

A Before advice is executed before the method execution.

First, create a class which implements MethodBeforeAdvice interface.

package com.java2s.common;

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 method call.");
  }
}

Then, we create the AOPBeforeMethod bean in the xml configuration file.

<bean id="aopBeforeMethodBean" class="com.java2s.aop.AOPBeforeMethod" />

To use the AOPBeforeMethod class we have to install it by using org.springframework.aop.framework.ProxyFactoryBean as follows.

  <bean id="myServiceProxy" 
                 class="org.springframework.aop.framework.ProxyFactoryBean">

    <property name="target" ref="myService" />

    <property name="interceptorNames">
      <list>
        <value>aopBeforeMethodBean</value>
      </list>
    </property>
  </bean>

Full source code

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

  <bean id="myService" class="com.java2s.common.PrinterService">
    <property name="name" value="printerName" />
    <property name="url" value="http://www.java2s.com" />
  </bean>

  <bean id="aopBeforeMethodBean" class="com.java2s.common.AOPBeforeMethod" />

  <bean id="myServiceProxy" 
                 class="org.springframework.aop.framework.ProxyFactoryBean">

    <property name="target" ref="myService" />

    <property name="interceptorNames">
      <list>
        <value>aopBeforeMethodBean</value>
      </list>
    </property>
  </bean>
</beans>

Run the main function again.

From the result we can see that the AOPBeforeMethod's before() method is executed before every myService's methods.

After returning advice

The following code shows how to use After returning advice. After returning advice will execute after the method is returned a result.

First, create a class which implements AfterReturningAdvice interface.

package com.java2s.common;

import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;

public class AOPAfterMethod implements AfterReturningAdvice
{
  @Override
  public void afterReturning(Object returnValue, Method method,
    Object[] args, Object target) throws Throwable {
          System.out.println("AOPAfterMethod : After method call.");
  }
}

Then, install the AOPAfterMethod class in the Bean configuration file.

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

  <bean id="myService" class="com.java2s.common.PrinterService">
    <property name="name" value="printerName" />
    <property name="url" value="http://www.java2s.com" />
  </bean>

  <bean id="aopAfterMethodBean" class="com.java2s.common.AOPAfterMethod" />

  <bean id="myServiceProxy" 
                class="org.springframework.aop.framework.ProxyFactoryBean">

    <property name="target" ref="myService" />

    <property name="interceptorNames">
      <list>
        <value>aopAfterMethodBean</value>
      </list>
    </property>
  </bean>
</beans>

Run the main function again. Here is the output.

From the result we can see that the AOPAfterMethod's afterReturning() method is executed after every myService's methods returns a result.

After throwing advice

The following code shows how to use After throwing advice. After throwing advice will execute after the method throws an exception.

First, create a class which implements ThrowsAdvice interface, and create a afterThrowing method to hijack the IllegalArgumentException exception.

package com.java2s.common;

import org.springframework.aop.ThrowsAdvice;

public class AOPThrowException implements ThrowsAdvice {
  public void afterThrowing(IllegalArgumentException e) throws Throwable {
    System.out.println("AOPThrowException : Throw exception call.");
  }
}

Then, install the AOPThrowException in Bean configuration file.

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

  <bean id="myService" class="com.java2s.common.PrinterService">
    <property name="name" value="printerName" />
    <property name="url" value="http://www.java2s.com" />
  </bean>

  <bean id="aopThrowExceptionBean" class="com.java2s.common.AOPThrowException" />

  <bean id="myServiceProxy" 
                 class="org.springframework.aop.framework.ProxyFactoryBean">

    <property name="target" ref="myService" />

    <property name="interceptorNames">
      <list>
        <value>aopThrowExceptionBean</value>
      </list>
    </property>
  </bean>
</beans>

Run the code and here is the output.

Printer Name : printerName
Printer URL : http://www.java2s.com
AOPThrowException : Throw exception call.

From the result we can see that Spring IoC container runs the AOPThrowException's afterThrowing() method when myService's methods throws an exception.

Around advice

The following code shows how to use Around advice. Around advice combines all three advices above, and execute during method execution.

First, create a class which implements MethodInterceptor interface.

public Object invoke(MethodInvocation methodInvocation) throws Throwable method is called for each method call and we have to call the "methodInvocation.proceed();" to run the original method, otherwise the original method will not run.

package com.java2s.common;

import java.util.Arrays;

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("Method name : "
        + methodInvocation.getMethod().getName());
    System.out.println("Method arguments : "
        + Arrays.toString(methodInvocation.getArguments()));

    System.out.println("AOPAroundMethod : Before method call.");

    try {
      // proceed to original method call
      Object result = methodInvocation.proceed();

      // same with AfterReturningAdvice
      System.out.println("AOPAroundMethod : after call.");

      return result;

    } catch (IllegalArgumentException e) {
      System.out.println("AOPAroundMethod : Throw exception call.");
      throw e;
    }
  }
}

Here is the xml Bean configuration file to install the Around Advice AOP.

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

  <bean id="myService" class="com.java2s.common.PrinterService">
    <property name="name" value="printerName" />
    <property name="url" value="http://www.java2s.com" />
  </bean>

  <bean id="aopAroundMethodBean" class="com.java2s.common.AOPAroundMethod" />

  <bean id="myServiceProxy" 
                class="org.springframework.aop.framework.ProxyFactoryBean">

    <property name="target" ref="myService" />

    <property name="interceptorNames">
      <list>
        <value>aopAroundMethodBean</value>
      </list>
    </property>
  </bean>
</beans>

Run the main function, here is the output.



Download AOP_Around.zip