Spring 动态切入点讲解

来源:互联网 发布:灯珠花 淘宝 编辑:程序博客网 时间:2024/05/17 02:58

如果我们需要根据方法的参数不同而决定事都进行切入,而不是不管方法是什么参数全部切入的话,我们就需要使用动态切入点,在每次方法调用时候都进行检查(确切的说是参数检查),;来决定是否执行通知

BeanOne.java

package DynamicPointCutAdvisor;

public class BeanOne {
   
public void foo(){
       System.out.println(
"foo-one");
   }

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

   
public void dynamic(int x){
       System.out.println(x);
   }

}

 动态切入点:

package DynamicPointCutAdvisor;

import java.lang.reflect.Method;

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

public class SimpleDynamicPointcut extends DynamicMethodMatcherPointcut {

    
    
//静态方法检查,为避免每次调用bar方法是都进行一次检测,导致效率降低
    public boolean matches(Method method, Class cls) {
        
return "dynamic".equals(method.getName());
    }

    
//当参数不为100时候,进行切入
    public boolean matches(Method method, Class cls, Object[] obj) {
        
int x=((Integer)obj[0]).intValue();
        
return (x!=100);
    }

    
public ClassFilter getClassFilter(){
        
return new ClassFilter(){
            
public boolean matches(Class cls){
                
return cls==BeanOne.class;
            }

        }
;
    }


}

环绕通知:

package DynamicPointCutAdvisor;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class SimpleAdvise implements MethodInterceptor {

    
public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println(
"before");
        Object retVal
=invocation.proceed();
        System.out.println(
"after");
        
return retVal;
    }


}

测试代码:

package DynamicPointCutAdvisor;

import org.aopalliance.aop.Advice;
import org.springframework.aop.Advisor;
import org.springframework.aop.Pointcut;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.DefaultPointcutAdvisor;

public class Test {

    
/**
     * 
@param args
     
*/

    
public static void main(String[] args) {
         BeanOne one
=new BeanOne();
        
         BeanOne proxyOne;
    
         
         Pointcut pc
=new SimpleDynamicPointcut();
         Advice advice
=new SimpleAdvise();
         Advisor advisor
=new DefaultPointcutAdvisor(pc,advice);
         
         
         
//创建BeanOne代理
         ProxyFactory pf1=new ProxyFactory();
         pf1.addAdvisor(advisor);
         pf1.setTarget(one);
         proxyOne
=(BeanOne)pf1.getProxy();
         
     
         
         
         proxyOne.dynamic(
100);
         System.out.println(
"-------------------");
         proxyOne.dynamic(
101);
         System.out.println(
"-------------------");
         proxyOne.bar();

    }


}

运行结果:

100
-------------------
before
101
after

-------------------
bar-one

后记

如果我们在切入点类中的方法检查代码中加入提示,如:

package DynamicPointCutAdvisor;

import java.lang.reflect.Method;

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

public class SimpleDynamicPointcut extends DynamicMethodMatcherPointcut {

    
    
//静态方法检查,为避免每次调用bar方法是都进行一次检测,导致效率降低
    public boolean matches(Method method, Class cls) {
        System.out.println(
"static check for "+method.getName());
        
return "dynamic".equals(method.getName());
    }

    
//当参数不为100时候,进行切入
    public boolean matches(Method method, Class cls, Object[] obj) {
        System.out.println(
"dynamic check for "+method.getName());
        
int x=((Integer)obj[0]).intValue();
        
return (x!=100);
    }

    
public ClassFilter getClassFilter(){
        
return new ClassFilter(){
            
public boolean matches(Class cls){
                
return cls==BeanOne.class;
            }

        }
;
    }


}


可以看到结果如下:

static check for dynamic
static check for bar
static check for foo
static check for clone
static check for toString
static check for dynamic

dynamic check for dynamic
100
-------------------
dynamic check for dynamic
before
101
after
-------------------
static check for bar
bar-one

可以看到,红色部分代表静态方法类型检查,绿色代表动态方法类型检查

当我们实现了静态检查|(public boolean matches(Method method, Class cls))时候,动态类型对不匹配的方法,如本例中的bar不再进行动态检查,提高了效率,如果没有public booleanmatches(Method method, Class cls)方法,则所有方法势必都会进行类型检查,不仅降低效率,还有可能因为方法参数的不同导致异常(如bar是没有参数的,使用动态检查中的 intx=((Integer)obj[0]).intValue();就会出现异常)