跟我学aspectj之八 -----控制流cfow,cfowbelow

一、序言

     cflow我认为是aspectj中最难理解的一个概念,至少我是这么认为的。当初刚接触aspectj的时候,可谓是为之颠倒,不只大家是否有相同的感觉。但有一点不可否认的就是:他觉得是aspectj强大功能之一。 他可以做到Spring AOP无法做到的场景。


二、控制流

     什么叫控制流? 相信很多不理解cflow的同学跟我一样,刚开始也是卡在这里,那么本节,我们就先理清这个概念。先看一段代码:

  

package com.aspectj.demo.test;

import org.junit.Test;

public class TestCfow {

	
	public void foo(){
		System.out.println("foo......");
	}
	
	public void bar(){
		foo();
		System.out.println("bar.........");
	}
	
	@Test
	public void testMethod(){
		bar();
		foo();
	}

}

    请用流程图画出testmethod()的流程,相信这个大家都画的出来吧?


那么现在你看着你画的图,我告诉你:这就是testMehtod()的控制流。那么cfow(execution(* testMethod())) 就是获取testMethod()的控制流。他将拦截到testMethod中的每行代码(包括:他流程里面调用的其它其他方法的流程,不管调用层次有多深,都属于他的控制流)。

       ps: 其实这里说是每行代码是不准的,其实是每行代码编译后的字节码。比如System.out.println() 其实编译后是3句话。

三、demo说明      

       首先,我们来看下bar的控制流,用我们的老办法。看招:

    

package com.aspectj.demo.aspect;

public aspect CfowAspect {

	pointcut barPoint() :  execution(* bar(..));
	pointcut fooPoint() : execution(* foo(..));
	pointcut barCfow() : cflow(barPoint());//cflow的参数是一个pointcut
	pointcut fooInBar() : barCfow() && fooPoint();  //获取bar流程内的foo方法调用
	
	
	before() : barCfow(){
		System.out.println("Enter:" + thisJoinPoint);
	}
	
}

    运行一下testCfow().看看是什么结果?



尼玛,太坑爹了, StackOverFow了。 哈哈,相信很多同学刚用cfow()的时候也出现这个问题吧??  其实笔者是故意给你们留的这个陷阱。 那么为什么会溢出勒?其实是这样的:cflowAspect织入了 Bar(). 所以他也算是bar的控制流的一部分, 这样一来,他就自己拦截自己,形成一个死循环,所以就溢出了。恍然一个大悟吧!


      那我们如何解决这个问题勒?记得上一节讲过的within么? 让我们修改一下代码.

	pointcut barCfow() : cflow(barPoint()) && !within(CfowAspect);

  再次运行testMehtod(),打印结果如下:

Enter:execution(void com.aspectj.demo.test.TestCfow.bar())
Enter:call(void com.aspectj.demo.test.TestCfow.foo())
Enter:execution(void com.aspectj.demo.test.TestCfow.foo())
Enter:get(PrintStream java.lang.System.out)
Enter:call(void java.io.PrintStream.println(String))
foo......
Enter:get(PrintStream java.lang.System.out)
Enter:call(void java.io.PrintStream.println(String))
bar.........
foo......

  每条打印,都可以看出是拦截的那句话,同时这个结果也验证了我给大家PS的那句话。始终要记得:aspectj是静态织入,所以他拦截的是字节码~。


    现在我们改变一下需求:  只拦截bar方法调用里面的foo()方法,也就是说我们testMethod()里面的foo() 调用不要拦截。

 

package com.aspectj.demo.aspect;

public aspect CfowAspect {

	pointcut barPoint() :  execution(* bar(..));
	pointcut fooPoint() : execution(* foo(..));
	pointcut barCfow() : cflow(barPoint()) && !within(CfowAspect);//cflow的参数是一个pointcut
	pointcut fooInBar() : barCfow() && fooPoint();  //获取bar流程内的foo方法调用
	
	
	before() : fooInBar(){
		System.out.println("Enter:" + thisJoinPoint);
	}
	
}

运行一下TestCflow。 

Enter:execution(void com.aspectj.demo.test.TestCfow.foo())
foo......
bar.........
foo......


发现是不是只有bar方法里面的foo()被拦截了?  用Spring AOP你就无法实现这个需求吧??  是不是突然觉得aspectj真的很强大??但是我还是要说:这只是他强大的表现之一,冰山一角。 但是他绝对是使用频率最高的功能之一。



四、总结

       cfow()获取的是一个控制流程。他很少几乎不单独使用,一般与其他的pointcut 进行 &&运算。若要单独使用,一定要记得用!with()剔除asepct 本身。他是我最喜欢,也是我用的最多的功能,在实际的应用中也用的最广,请好好掌握他。

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值