关于Spring的ControlFlowPointcut的效率问题
?????? 利用Spring的AOP支持,可以在方法调用前后,或者在抛出异常时执行一些额外的代码。
?????? 以上特性不过是代理模式的灵活使用而已,理解起来比较自然,没有太大难度。
?????? 而关于ControlFlowPointcut这个特性,也就是传说中的“控制流切入点”,这个特性理解起来颇有一些意思,今天搞了一个下午,终于搞明白了这里的运行原理,记录一下备忘。
?????? 林信良的《Spring2.0技术手册》里面4.3.3节有一个例子,我看到网上很多人说这个例子有错误,实际上这个例子完全正确,没有任何错误。
?????? 举例来说:
???????
public class A{ public void hello(){ System.out.println("A says:hello..."); }}public class B{ private A a; public void setA(A a){ this.a=a; } public void bSayHello(){ a.hello(); }}public class Test(){ public static void main(String[] args){ A a=new A(); a.hello();//第一处 B b=new B(); b.setA(a); b.bSayHello();//第二处 }}
???
???????? ControlFlowPointcut要实现的目的是:第一处不执行其它动作(比如在hello()方法的调用前后利用logger记录日志);而第二处可以根据Spring的配置文件执行一些其它的动作。
??????? 那么,这里的问题是,Spring是怎么知道hello()方法是从哪儿被调用的呢?
??????? 唯一可能的解释就是,当hello()方法被调用的时候,Spring取得了方法的调用堆栈,然后在堆栈里面去匹配,看看方法是从哪个类调用进来的。来翻spring-core***.jar里面ControlFlowFactory.java的一段源码:
???????
?
??????? 好吧,啥也不说了。。。
??????? 如此猥琐的手法都搞出来了,为了搞明白某个方法是从哪个类中的哪个方法进行调用的,居然自己手动创建了Throwable()对象,然后通过getStackTrace()拿到调用栈!!!
??????? 这还没完,拿到调用栈之后然后再用for循环去进行字符串匹配!!!
??????? 显而易见,这种处理手法相当猥琐,并且运行效率显然比较低下。
??????? 看来大牛们一直说尽量避免使用ControlFlowPointcut还是有几份道理的啊(据说运行效率会降低5到10倍---因为Spring自己在调用栈里面倒腾),佩服佩服!
??????? 谨记之,以供同仁参考。
漠漠 加油 小蜜 加油