spring AOP 动态代理机制导致的spring事务失效的问题原理分析

先上两张图,看懂图的同学可以不继续往下看了。

  这里说一下问题。springMVC的service层中一个类提供了多个方法,a()、b()、c()、d()。其中方法a上未显示声明事务(@Transactional),而方法b()、c()、d()都显示声明了事务。并且spring的注解扫描和bean的实例化过程都没有问题(排除其他问题产生的影响)。

  此时controller层调用使用此service对象调用方法a(),其中处理逻辑是  a()->b()->c()->d(),有这样的调用关系。结果就是这个从方法a开始的调用没有添加上事务。

  是的,乍一看有点奇怪,仔细分析一下,就清晰了。

  这还得从spring AOP的实现原理说起,spring AOP是基于动态代理实现的,分jdk和cglib两种,简单来说,jdk只对接口代理,cglib可以对普通类代理。事务的实现是通过代理类(proxy)来实现的,当一个添加注解的类被动态代理后,所有调用这个类对象的方式都是先执行代理类的开启事务(如果这个方法添加了事务),再进入被代理对象执行相应的方法。但是在被代理对象中调用本对象中的方法时,不会再去通过代理类来执行(如上图1),由于事务是通过代理类完成的,所以如果父调用没有开启,后面的方法调用是不会再开启事务的。上述例子中方法a没有声明事务,所以代理类中没有对a方法开启事务,进入被代理系统后,继而调用方法b、c、d,虽然方法b、c、d上有事务注解,但因为是原代理类内部方法调用,并没有返回代理类去开启事务。故事务“失效”。

  图二是理想的用法,可以在被代理类中通过AopContext.currentProxy();得到当前类的代理类,然后继续从代理类执行对应的有事务的方法。

  P.S.今天是个记得纪念的日子,一个项目生产环境上出了事务问题,在这个问题上我pk掉了我的上司也是我们部门的技术老大。工作不到3年,为自己感到骄傲。

  

猜你喜欢

转载自www.cnblogs.com/hibugs/p/8920643.html