也就是說我們首先調用的是AOP代理對象而不是目標對象,首先執行事務切面,事務切面內部通過TransactionInterceptor環繞增強進行事務的增強,即進入目標方法之前開啟事務,退出目標方法時提交/回滾事務
1、測試代碼如下:
1 public interface AService { 2 public void a(); 3 public void b(); 4 } 5 6 @Service() 7 public class AServiceImpl1 implements AService{ 8 @Transactional(propagation = Propagation.REQUIRED) 9 public void a() { 10 this.b(); 11 } 12 @Transactional(propagation = Propagation.REQUIRES_NEW) 13 public void b() { 14 } 15 }
2、問題:
目標對象內部的自我調用將無法實施切面中的增強,如圖所示
此處的this指向目標對象,因此調用this.b()將不會執行b事務切面,即不會執行事務增強,因此b方法的事務定義“@Transactional(propagation = Propagation.REQUIRES_NEW)”將不會實施,即結果是b和a方法的事務定義是一樣的(我們可以看到事務切面只對a方法進行了事務增強,沒有對b方法進行增強)
Q1:b中的事務會不會生效?
A1:不會,a的事務會生效,b中不會有事務,因為a中調用b屬於內部調用,沒有通過代理,所以不會有事務產生。
Q2:如果想要b中有事務存在,要如何做?
A2:<aop:aspectj-autoproxy expose-proxy=“true”> ,設置expose-proxy屬性為true,將代理暴露出來,使用AopContext.currentProxy()獲取當前代理,將this.b()改為((UserService)AopContext.currentProxy()).b()
3、解決方案
此處a方法中調用b方法時,只要通過AOP代理調用b方法即可走事務切面,即可以進行事務增強,如下所示:
判斷一個Bean是否是AOP代理對象可以使用如下三種方法:
AopUtils.isAopProxy(bean) : 是否是代理對象;
AopUtils.isCglibProxy(bean) : 是否是CGLIB方式的代理對象;
AopUtils.isJdkDynamicProxy(bean) : 是否是JDK動態代理方式的代理對象;
4、通過ThreadLocal暴露Aop代理對象
1、開啟暴露Aop代理到ThreadLocal支持(如下配置方式從spring3開始支持)
2、修改我們的業務實現類
this.b();-----------修改為--------->((AService) AopContext.currentProxy()).b();