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

相关文章
相关标签/搜索