Dynamic Pointcut Example in Spring AOP

The following example illustrates using a dynamic pointcut. The difference between a static pointcut is that, in dynamic pointcut you can filter the method call instead of just the method. For example, you can apply the advice to ding(10); but not ding(20); In simple words, here you will get access to the argument values.
To achieve this, the dynamic pointcut is called every time the method is invoked because every time it is invoked, the argument value might change.

Theme of the application

The theme of the application is to illustrate a simple dynamic pointcut. Here, the method for which the advice will be applied is ding(). The prototype of this method is as follow

public void ding(int x);

This method takes an int parameter and prints the value. Now, an around advice is applied to it.
This advice contains the code that logs two messages. One message is printed before the method is invoked and the other after the method is invoked.
Now, we will be writing a pointcut to let the advice apply to only when the value passed to ding() is other than 100.

Create a project in eclipse

  1. File -> New -> Project -> Java Project
  2. Give the project name spring41 and click Finish 
  3. Now, the project is created.
  4. Under the Project Explorer (in the sidebar) you will see spring41. If you aren't able to see Project Explorer, go to Window menu -> Show view -> Project Explorer.
  5. Right click on the spring41 and click Properties
  6. On the left side, click on Java Build Path.
  7. Select the Libraries tab and then click on Add External Jars
  8. Now, add these jar files starting with: spring-core, aop-alliance, spring-aop, commons-logging
  9. Click on OK and then you are read

To create a class

In the Project Explorer, navigate to spring41 and right click on spring41. Then go to New -> Class and give the name of the class as defined below.
 

Project structure 


 

SimpleBean.java

This is the target bean class that contains the method ding() for which the advice is wrapped.
package spring41;

public class SimpleBean {

    public void ding(int x)
    {
        System.out.println("The value is "+x);
    }
   
}
 

MySimpleAdvice.java - Around advice 

package spring41;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class MySimpleAdvice implements MethodInterceptor {

// Create a log object
private static Log log;

    static
    {
        // Create the log object
        log=LogFactory.getLog(MySimpleAdvice.class);
    }
   
    public Object invoke(MethodInvocation mi) throws Throwable
    {
    // Print the method call
    String name=mi.getMethod().getName()+"("+mi.getArguments()[0]+")";
   
    Object val=null;
   
        if(log.isInfoEnabled())
        {
            // log the detail
            log.info("Invoking method "+name);
           
            // call the method
            val=mi.proceed();
           
            // print method is invoked
            log.info("Method is invoked.");
        }
   
    // return val
    return val;
    }
   
}
 

SimpleDynamicPointcut.java

This class defines to which the advice should be applied.
package spring41;

import java.lang.reflect.Method;

import org.springframework.aop.ClassFilter;
import org.springframework.aop.support.DynamicMethodMatcherPointcut;

public class SimpleDynamicPointcut extends DynamicMethodMatcherPointcut {

    // Filter the target class first
    @Override
    public ClassFilter getClassFilter() {
        return new ClassFilter(){
            @Override
            public boolean matches(Class<?> cls)
            {
                // Only SimpleBean class, not other classes
                return cls.getName().endsWith("SimpleBean");
            }
        };
    }

    @Override
    public boolean matches(Method method, Class<?> cls, Object[] args) {
      
        // Filter the method name, only for ding()
        // advice should be applied
        if(!method.getName().equals("ding")) return false;
      
        // Get the first argument
        int x=(Integer)args[0];
      
        // If x!=100 then it matches, else doesn't
        return x!=100;
    }

}
 
First, the getClassFilter() method is executed first and next matches() is executed. Here as you can see, the last argument is args which is of type Object[]. These are argument values passed to the method in order.

SpringPrg.java - Main class

package spring41;

import org.springframework.aop.Advisor;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;

public class SpringPrg {

    public static void main(String args[])
    {
        // Create target bean object
        SimpleBean sb=new SimpleBean();
       
        // Create the pointcut object
        SimpleDynamicPointcut pointcut=new SimpleDynamicPointcut();
       
        // Create advice object
        MySimpleAdvice advice=new MySimpleAdvice();
        Advisor advisor=new DefaultPointcutAdvisor(pointcut,advice);

        // Create ProxyFactory
        ProxyFactory pf=new ProxyFactory();
       
        // Set the target object
        // Only methods in this object will be filtered
        pf.setTarget(sb);
       
        // Add the advisor
        pf.addAdvisor(advisor);
       
        // Get the proxied object
        SimpleBean bean=(SimpleBean)pf.getProxy();
       
        // Logging will be displayed
        // since x!=100
        bean.ding(10);
        bean.ding(101);
       
        // logging will not be displayed
        bean.ding(100);
    }
   
}

When you call ding(10) and ding(101) the advice will be applied, but not for ding(100).

Output


Apr 13, 2014 1:25:28 PM spring41.MySimpleAdvice invoke
INFO: Invoking method ding(10)
The value is 10
Apr 13, 2014 1:25:28 PM spring41.MySimpleAdvice invoke
INFO: Method is invoked.
Apr 13, 2014 1:25:28 PM spring41.MySimpleAdvice invoke
INFO: Invoking method ding(101)
The value is 101
Apr 13, 2014 1:25:28 PM spring41.MySimpleAdvice invoke
INFO: Method is invoked.
The value is 100

Also see method static pointcut example

No comments: