1. 程式人生 > >Spring Aop巢狀呼叫時沒有生效

Spring Aop巢狀呼叫時沒有生效

轉載自:https://blog.csdn.net/hong10086/article/details/78424481

  Spring AOP在同一個類裡自身方法相互呼叫時是無法攔截的。比如在一個 Service 類的 doSomething1() 方法中通過doSomething2(); 語句呼叫了同一個類中的 doSomething2 方法,執行時通過除錯發現 doSomething1 方法的執行前後正常地執行了自定義的 around advice,但是在 doSomething2 方法執行前後並未如期望的那樣執行自定義的 around advice。原因呢?
  Spring的代理實現有兩種:一是基於 JDK Dynamic Proxy 技術而實現的;二是基於CGLIB 技術而實現的。來基於JDK Dynamic Proxy 的動態代理看下Spring AOP怎麼弄的。

程式碼如下:

public interface ICustomerService {  
    public void doSomething1();  
    public void doSomething2();  
}  
 public class CustomerServiceImpl implements ICustomerService {  
  
    public void doSomething1() {  
        System.out.println("Inside CustomerServiceImpl.doSomething1()");  
        doSomething2();  
    }  
  
    public void doSomething2() {  
        System.out.println("Inside CustomerServiceImpl.doSomething2()");  
    }  
}  

  下面來模擬動態生成代理類的過程,若使用 JDK Dynamic Proxy,這一過程是在執行時進行的。CustomerServiceImpl 類物件的代理類:

 public class CustomerServiceProxy implements ICustomerService {  
  
    private ICustomerService customerService;  
  
    public void setCustomerService(ICustomerService customerService) {  
        this.customerService = customerService;  
    }  
  
    public void doSomething1() {  
        doBefore();  
        customerService.doSomething1();  
        doAfter();  
    }  
  
    public void doSomething2() {  
        doBefore();  
        customerService.doSomething2();  
        doAfter();  
    }  
  
    private void doBefore() {  
        // 例如,可以在此處開啟事務  
        System.out.println("do some important things before...");  
    }  
  
    private void doAfter() {  
        // 例如,可以在此處提交或回滾事務、釋放資源等等  
        System.out.println("do some important things after...");  
    }  
}  

  Spring實際上是在容器中生成了CustomerServiceProxy,將原始的CustomerServiceImpl設定到了CustomerServiceProxy中。
  doSomething1()中呼叫doSomething2()方法,它隱含的意思是this.doSomething2(),在CustomerServiceImpl類中 this關鍵字表示的是當前這個CustomerServiceImpl類的例項。那程式會去執行 CustomerServiceImpl 類中的 doSomething2() 方法了,而不會去執行 CustomerServiceProxy 類中的 doSomething2()方法。
  在使用 Spring AOP 的時候,從 IOC 容器中獲取的 Service Bean 物件其實都是代理物件,而不是那些 Service Bean 物件本身,也就是說獲取的並不是被代理物件或代理目標。當在Service 類中使用 this 關鍵字巢狀呼叫同類中的其他方法時,由於 this 關鍵字引用的並不是該 Service Bean 物件的代理物件,而是其本身,故 Spring AOP 是不能攔截到這些被巢狀呼叫的方法的。

  怎麼解呢?參考 https://blog.csdn.net/huangjinlong77/article/details/42707571