Spring中在同一个类中两个方法调用,会导致代理失效,比如同一个类中一个方法A调用另外一个带事务的方法B,会发现B方法的事务不生效;同一个类中一个方法A调用另外一个带注解的清除缓存的方法B,会发现清除缓存不成功。
Spring中仅支持方法级别的代理。
Spring中代理是动态代理,也就是在运行时生成代理,代理可以大概使用以下代码来描述下:
@Service public class A { public void a() { ...; b(); ...; } @Transactional public void b() { ...; } }
而在运行时生成的代理大概如下:
public class A$Proxy { A serviceA = new A(); public void a() { serviceA.a(); } public void b() { transaction start(); serviceA.b(); transaction end(); } }
如果我们调用A这个Bean其实调用的是A$Proxy,对于a方法的调用其实是调用的A中的a方法,而A中的a调用的是A中的b方法,并没有调用A$Proxy中的b方法来实施事务。
解决办法:
开启expose-proxy后,我们代码需要类似如下处理:
@Service public class A { public void a() { ...; ((A)AopContext.currentProxy()).b(); ...; } @Transactional public void b() { ...; } }
这种方法在Spring中的实现大概是:Spring在代理使用的时候,会将当前代理设置到AopContext中去: AopContext.setCurrentProxy(proxy)
,所以在我们上面修改后的代码里 AopContext.currentProxy()
就可以拿到A$Proxy,再调用b方法的时候,就是调用的A$Proxy中的增强过的b方法了。