spring aop 嵌套調用的問題 (同一方法內調用切面切不到)

在開發基於 Spring 的應用的過程當中碰到了一個讓我困惑了很久的問題,我在一個 Service 類的 doSomething1() 方法中經過
this.doSomething2(); 語句調用了同一個類中的 doSomething2 方法,運行時經過調試發現 doSomething1 方法的執行先後正常地執行了自定義的 around 裝備,可是在 doSomething2 方法執行先後並未如我所指望的那樣執行自定義的 around advice 。今天終於恍然大悟,把它看成筆記寫下來。Spring 的代理實現有兩種:一是基於 JDK Dynamic Proxy 技術而實現的;二是基於 CGLIB 技術而實現的。今天的目標是探索基於 JDK Dynamic Proxy 的動態代理。首先來看看如何本身動手實現一個對 Service Bean 對象的動態代理。爲了可以更清楚地看到 Spring AOP 動態代理的本質,我決定不使用 JDK 中提供的 Dynamic Proxy API,就使用最普通的 java 代碼來模擬一個動態代理實例。java

首先,來建立一個須要代理的接口:ide

 

package demo.interf;    
public interface ICustomerService {  
    public void doSomething1();  
    public void doSomething2();  
}  

 而後就是具體服務類:this

 

package demo.interf.impl;  
  
import demo.interf.ICustomerService;  
  
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,這一過程是在運行時進行的。spa

CustomerServiceImpl 類對象的代理類:  代理

 

package demo.interf.impl;  
  
import demo.interf.ICustomerService;  
  
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...");  
    }  
  
}  

 使用代理對象調用業務邏輯操做的客戶端程序:調試

 

package test;  
  
import demo.interf.ICustomerService;  
import demo.interf.impl.CustomerServiceImpl;  
import demo.interf.impl.CustomerServiceProxy;  
  
public class TestProxy {  
      
    public static void main(String[] args) {  
        // 建立代理目標對象。對於Spring來講,這一工做  
        // 是由Spring DI容器完成的。  
        ICustomerService serviceProxyTarget = new CustomerServiceImpl();  
  
        // 建立代理對象。對於Spring來講,這一工做  
        // 也是由Spring DI容器完成的。  
        CustomerServiceProxy serviceProxy = new CustomerServiceProxy();  
        serviceProxy.setCustomerService(serviceProxyTarget);  
        ICustomerService serviceBean = (ICustomerService) serviceProxy;  
  
        // 調用業務邏輯操做  
        serviceBean.doSomething1();  
    }  
}  
 好了,完成了。如今以調試方式運行這個應用,你會發如今 doSomething1() 中調用 doSomething2() 方法的時候並未去執行CustomerServiceProxy 類的 doBefore()、doAfter() 方法。再來看看這句關鍵代碼:doSomething2(); 把它隱含的意思也表達出來吧:this.doSomething2(); 哦,我明白了,在 CustomerServiceImpl 類中 this 關鍵字表示的是當前這個CustomerServiceImpl類的實例。那程序固然就會去執行 CustomerServiceImpl 類中的 doSomething2() 方法了,而不會去執行 CustomerServiceProxy 類中的 doSomething2() 方法!!

在使用 Spring AOP 的時候,咱們從 IOC 容器中獲取的 Service Bean 對象其實都是代理對象,而不是那些 Service Bean 對象自己,也就是說獲取的並非被代理對象或代理目標。當我在本身的 Service 類中使用 this 關鍵字嵌套調用同類中的其餘方法時,因爲 this 關鍵字引用的並非該 Service Bean 對象的代理對象,而是其自己,故 Spring AOP 是不能攔截到這些被嵌套調用的方法的。code

相關文章
相關標籤/搜索