Spring的transactional注解自调用失效的原理

我先说一下我自己的理解:失效的关键是Spring的AOP会生成两个对象(这是Java原本的代理方式),所以有两个this,一个是代理类的this,一个是原本类的this,调用原本类的方法的时候,用了原本类的this。而如果只有一个代理增强类的话,就只有一个this了,那么利用多态性就可以避免事务失效了。

转载自:https://blog.csdn.net/seelye/article/details/40144817

 好了,现在总结一下现象:

     1、ServiceA类为Web层的Action服务

     2、Action调用了ServiceA的方法A,而方法A没有声明事务(原因是方法A本身比较耗时而又不需要事务)

     3、ServiceA的方法A调用了自己的方法B,而方法B声明了事务,但是方法B的事务声明在这种情况失效了。

     4、如果在方法A上也声明事务,则在Action调用方法A时,事务生效,而方法B则自动参与了这个事务。 

 

       我让他先把A也加上事务声明,决定回来自己再测一下。

     

       这个问题,表面上是事务声明失效的问题,实质上很可能是Spring的AOP机制实现角度的问题。我想到很久以前研究Spring的AOP实现时发现的一个现象:对于以Cglib方式增强的AOP目标类,会创建两个对象,一个事Bean实例本身,一个是Cglib增强代理对象,而不仅仅是只有后者。我曾经疑惑过这一点,但当时没有再仔细探究下去。

     

      我们知道,Spring的AOP实现方式有两种:1、Java代理方式;2、Cglib动态增强方式,这两种方式在Spring中是可以无缝自由切换的。Java代理方式的优点是不依赖第三方jar包,缺点是不能代理类,只能代理接口。

 

      Spring通过AopProxy接口,抽象了这两种实现,实现了一致的AOP方式:

 

 

现在看来,这种抽象同样带了一个缺陷,那就是抹杀了Cglib能够直接创建普通类的增强子类的能力,Spring相当于把Cglib动态生成的子类,当普通的代理类了,这也是为什么会创建两个对象的原因。下图显示了Spring的AOP代理类的实际调用过程:

 

 

 

因此,从上面的分析可以看出,methodB没有被AopProxy通知到,导致最终结果是:被Spring的AOP增强的类,在同一个类的内部方法调用时,其被调用方法上的增强通知将不起作用。

    

      而这种结果,会造成什么影响呢:

      1:内部调用时,被调用方法的事务声明将不起作用

      2:换句话说,你在某个方法上声明它需要事务的时候,如果这个类还有其他开发者,你将不能保证这个方法真的会在事务环境中

      3:再换句话说,Spring的事务传播策略在内部方法调用时将不起作用。不管你希望某个方法需要单独事务,是RequiresNew,还是要嵌套事务,要Nested,等等,统统不起作用。

      4:不仅仅是事务通知,所有你自己利用Spring实现的AOP通知,都会受到同样限制。。。。

 

[解难]

     

      问题的原因已经找到,其实,我理想中的AOP实现,应该是下面这样:

 

只要一个Cglib增强对象就好,对于Java代理方式,我的选择是毫不犹豫的抛弃。

 

      至于前面的事务问题,只要避开Spring目前的AOP实现上的限制,要么都声明要事务,要么分开成两个类,要么直接在方法里使用编程式事务,那么一切OK。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值