Spring AOP本质(6)
版权声明:原创作品,如需转载,请与作者联系。否则将追究法律责任。 |
Spring AOP本质(5)-Pointcut
在前面四个例子中,只要实现一个Advice,然后调用ProxyFactory.addAdvice()方法为代理设定通知,不用设置切入点,从代理对上调用的方法就被通知到了。其原因就在于执行addAdvice()方法时,ProxyFactory会将Advice对象委派给addAdvistor()方法,后台会自动创建一个DefaultPointcutAdvistor实例,并将Advice加入其中。而默认的DefaultPointcutAdvistor会将切入点设为所有的方法。
假如我们不想通过代理来执行某些方法,也就是说,在执行某些方法的时候不通知,这时候该如何实现呢?
Spring提供一系列接口来实现这个目标。最主要的接口如下:
implements org.springframework.aop.Pointcut org.springframework.aop.ClassFilter org.springframework.aop.MethodMatcher 下面看看几个关键接口的定义:
1、切入点(Pointcut)
/**
* 切入点 */ public interface Pointcut { //切入点的一个单例 public static final Pointcut TRUE = TruePointcut.INSTANCE; //类过滤器 public ClassFilter getClassFilter(); //方法过滤器 public MethodMatcher getMethodMatcher(); } /** * 类过滤器 */ public interface ClassFilter { //类过滤器单例 public static final ClassFilter TRUE = TrueClassFilter.INSTANCE; //类匹配方法 public boolean matches(Class class1); } /** * 方法过滤器 */ public interface MethodMatcher { //方法过滤器单例 public static final MethodMatcher TRUE = TrueMethodMatcher.INSTANCE; //静态方法匹配方法 public boolean matches(Method method, Class class1); //判断静态还是动态匹配,返回true动态匹配,false静态匹配 public boolean isRuntime(); //对象(动态)匹配方法 public boolean matches(Method method, Class class1, Object aobj[]); } 2、通知者(Advisor)
/** * 通知者接口 */ public interface Advisor { //切面是否为per instance public boolean isPerInstance(); //获取切面上的通知 public Advice getAdvice(); } /** * 通知者子接口,Spring中标准的切面都应该实现此接口 */ public PointcutAdvisor extends Advisor { //获取通知者的切点 public Pointcut getPointcut(); } 为了看的明白,还是回顾一下框架图:
![]() 还有很多接口和类没有画出,这里简要说明下。
在org.springframework.aop.support包下,还有一些很重要的切点类,是Spring定义好的,几乎可以满足所用应用的需要。
DynamicMethodMatcherPointcut
NameMatchMethodPointcut Perl5RegexpMethodPointcut StaticMethodMatcherPointcut JdkRegexpMethodPointcut ControlFlowPointcut ComposablePointcut 与这些切点对应,还有一些切面类,名字都是以PointcutAdvisor结尾。
通过上面的原理图,简单查看一下API,就可以直到,通过通知Advice和切点Pointcut可以生成通知者Advisor。有了通知者,有了目标对象,就可以通过ProxyFactory生成代理对象。
下面给个例子看看Spring如何通过切点来选取类和方法的,并如通知所选取的方法。
例子:扩展StaticMethodMatcherPointcut,实现静态切入点过滤。
/** * 业务组件:BeanOne */ public class BeanOne { public void foo() { System.out.println("BeanOne的foo()被调用!"); } public void bar() { System.out.println("BeanOne的bar()被调用!"); } } /** * 业务组件:BeanTwo */ public class BeanTwo { public void foo() { System.out.println("BeanTwo的foo()被调用!"); } public void bar() { System.out.println("BeanTwo的bar()被调用!"); } } import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; /** * 自定义通知:Advice */ public class SimpleAdvice implements MethodInterceptor { public Object invoke(MethodInvocation invocation) throws Throwable { System.out.println(">> 业务方法调用前动作,被代理调用目标方法是: " + invocation.getMethod().getName()); Object retVal = invocation.proceed(); System.out.println(">> 业务方法调用结束后动作!"); return retVal; } } import java.lang.reflect.Method; import org.springframework.aop.ClassFilter; import org.springframework.aop.support.StaticMethodMatcherPointcut; /** * 自定义静态切入点:Pointcut */ public class SimpleStaticPointcut extends StaticMethodMatcherPointcut { public boolean matches(Method method, Class cls) { //类方法名为foo时候匹配 System.out.println("切入点方法匹配,正在匹配"+cls.getName()+"的"+method.getName()+"方法!"); return ("foo".equals(method.getName())); } public ClassFilter getClassFilter() { return new ClassFilter() { public boolean matches(Class cls) { System.out.println("切入点类匹配,正在匹配"+cls.getName()+"类!"); //BeanOne类匹配 return (cls == BeanOne.class); } }; } } 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 StaticPointcutExample { public static void main(String[] args) { //创建目标对象 BeanOne one = new BeanOne(); BeanTwo two = new BeanTwo(); //定义代理对象 BeanOne proxyOne; BeanTwo proxyTwo; //创建一个切入点 Pointcut pc = new SimpleStaticPointcut(); //创建一个通知 Advice advice = new SimpleAdvice(); //创建一个通知者(即通知和切入点的结合) Advisor advisor = new DefaultPointcutAdvisor(pc, advice); //创建一个代理工厂 ProxyFactory pf = new ProxyFactory(); //将方面加入工厂 pf.addAdvisor(advisor); //将目标加入工厂 pf.setTarget(one); //获取代理对象产品 proxyOne = (BeanOne) pf.getProxy(); //这个时候会进行匹配检查 //创建一个代理工厂 pf = new ProxyFactory(); pf.addAdvisor(advisor); pf.setTarget(two); proxyTwo = (BeanTwo) pf.getProxy(); /* org.springframework.aop.framework.ProxyFactory中 设置的代理目标一次仅能一个,这点不要犯迷糊,我查过源码了. */ //从代理产品上调用目标方法 proxyOne.foo(); proxyTwo.foo(); proxyOne.bar(); proxyTwo.bar(); } } 运行结果:
- Using JDK 1.4 collections 切入点类匹配,正在匹配com.apress.prospring.ch6.staticpc.BeanOne类! 切入点方法匹配,正在匹配com.apress.prospring.ch6.staticpc.BeanOne的foo方法! 切入点类匹配,正在匹配com.apress.prospring.ch6.staticpc.BeanOne类! 切入点方法匹配,正在匹配com.apress.prospring.ch6.staticpc.BeanOne的bar方法! 切入点类匹配,正在匹配com.apress.prospring.ch6.staticpc.BeanOne类! 切入点方法匹配,正在匹配com.apress.prospring.ch6.staticpc.BeanOne的hashCode方法! 切入点类匹配,正在匹配com.apress.prospring.ch6.staticpc.BeanOne类! 切入点方法匹配,正在匹配com.apress.prospring.ch6.staticpc.BeanOne的toString方法! 切入点类匹配,正在匹配com.apress.prospring.ch6.staticpc.BeanTwo类! 切入点类匹配,正在匹配com.apress.prospring.ch6.staticpc.BeanTwo类! 切入点类匹配,正在匹配com.apress.prospring.ch6.staticpc.BeanTwo类! 切入点类匹配,正在匹配com.apress.prospring.ch6.staticpc.BeanTwo类! 切入点类匹配,正在匹配com.apress.prospring.ch6.staticpc.BeanOne类! 切入点方法匹配,正在匹配com.apress.prospring.ch6.staticpc.BeanOne的foo方法! >> 业务方法调用前动作,被代理调用目标方法是: foo BeanOne的foo()被调用! >> 业务方法调用结束后动作! BeanTwo的foo()被调用! BeanOne的bar()被调用! BeanTwo的bar()被调用! Process finished with exit code 0 本文出自 “熔 岩” 博客,转载请与作者联系! 本文出自 51CTO.COM技术博客 |




leizhimin
博客统计信息
热门文章
最新评论
友情链接