`
ssxxjjii
  • 浏览: 950367 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

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 代码来模拟一个动态代理实例。

首先,来创建一个需要代理的接口:

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

 然后就是具体服务类:

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,这一过程是在运行时进行的。

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 是不能拦截到这些被嵌套调用的方法的。

分享到:
评论

相关推荐

    spring学习文档

    CGLib 采用非常底层的字节码技术,可以为一个类创建子类,并在子类中采用方法拦截技术拦截所有父类方法的调用,并顺势织入横切逻辑。 四、Spring 事务管理 Spring 事务管理主要通过三个接口:...

    深入理解Spring声明式事务:源码分析与应用实践

    在嵌套事务逻辑中,如果一个事务内的方法也被`@Transactional`注解,Spring会根据传播行为来决定如何处理。例如,`PROPAGATION_REQUIRED`会将新的方法调用加入到当前事务,而`PROPAGATION_NEW`则会启动一个新的独立...

    Spring-Reference_zh_CN(Spring中文参考手册)

    12.2.4. 不使用回调的基于Spring的DAO实现 12.2.5. 基于Hibernate3的原生API实现DAO 12.2.6. 编程式的事务划分 12.2.7. 声明式的事务划分 12.2.8. 事务管理策略 12.2.9. 容器资源 vs 本地资源 12.2.10. 在应用服务器...

    Spring 开发参考手册

    Spring 提供了一种轻量级的方式来管理和配置 Java 对象(Beans),并通过依赖注入(Dependency Injection, DI)和面向切面编程(Aspect-Oriented Programming, AOP)等机制来实现这一目标。 **Spring** 的核心功能...

    springtransaction 事务管理

    声明式事务管理依赖于Spring的AOP机制,它可以在不修改业务代码的情况下,通过代理对象拦截方法调用,实现事务的自动控制。AOP允许我们定义“切面”(Aspect),即关注点的模块化,如事务管理就是一个典型的横切...

    Spring中文帮助文档

    12.2.4. 不使用回调的基于Spring的DAO实现 12.2.5. 基于Hibernate3的原生API实现DAO 12.2.6. 编程式的事务划分 12.2.7. 声明式的事务划分 12.2.8. 事务管理策略 12.2.9. 容器资源 vs 本地资源 12.2.10. 在应用...

    Spring API

    12.2.4. 不使用回调的基于Spring的DAO实现 12.2.5. 基于Hibernate3的原生API实现DAO 12.2.6. 编程式的事务划分 12.2.7. 声明式的事务划分 12.2.8. 事务管理策略 12.2.9. 容器资源 vs 本地资源 12.2.10. 在应用...

    Spring.3.x企业应用开发实战(完整版).part2

    10.6.1 哪些方法不能实施Spring AOP事务 10.6.2 事务增强遗漏实例 10.7 数据连接泄漏 10.7.1 底层连接资源的访问问题 10.7.2 Spring JDBC数据连接泄漏 10.7.3 通过DataSourceUtils获取数据连接 10.7.4 通过...

    Spring事务源码解读.doc

    - **AOP代理**:Spring通过AOP(面向切面编程)实现事务的管理,当事务方法被调用时,Spring会创建一个代理对象,拦截方法调用并在适当的时候进行事务控制。 - **事务边界**:事务的边界由`@Transactional`注解...

    Spring 2.0 开发参考手册

    9.9.1. 对一个特定的 DataSource 使用错误的事务管理器 9.10. 更多的资源 10. DAO支持 10.1. 简介 10.2. 一致的异常层次 10.3. 一致的DAO支持抽象类 11. 使用JDBC进行数据访问 11.1. 简介 11.1.1. Spring ...

    cglib 动态代理

    4. **MethodProxy**:CGLib生成的代理对象会包含一个MethodProxy实例,这个对象可以调用实际的方法。在MethodInterceptor的`intercept`方法中,我们可以通过MethodProxy来调用目标方法。 5. **代理对象的创建**:...

    Spring3.x企业应用开发实战(完整版) part1

    10.6.1 哪些方法不能实施Spring AOP事务 10.6.2 事务增强遗漏实例 10.7 数据连接泄漏 10.7.1 底层连接资源的访问问题 10.7.2 Spring JDBC数据连接泄漏 10.7.3 通过DataSourceUtils获取数据连接 10.7.4 通过...

    spring chm文档

    Spring Framework 开发参考手册 Rod Johnson Juergen Hoeller Alef Arendsen Colin Sampaleanu Rob Harrop Thomas Risberg Darren Davison Dmitriy Kopylenko Mark Pollack Thierry Templier Erwin ...

    通用的报表缓存设计(Spring AOP + Redis)

    在`RedisProcess`类中,注入了`RedisTemplate`以操作Redis,并定义了一个`pointcutMethod()`方法作为切入点,它会拦截所有带有`RedisCache`注解的方法。`around()`方法作为环绕通知,负责在方法执行前后处理缓存逻辑...

    Spring的事务10种常见失效场景总结.zip

    5. **回调方法中的事务失效**:在Spring AOP中,后置处理器(AfterReturningAdvice)不能感知到事务,因此在这些回调方法中无法进行事务操作。如果需要在回调中处理事务,应考虑使用其他回调机制,如`@AfterThrowing...

    spring事务1

    9. **问题与解决**:在同一个类中,一个方法调用另一个方法时,AOP无法自动拦截内部方法,因为它们在同一个实例中执行。为解决此问题,可以使用`@Transactional(propagation = Propagation.REQUIRES_NEW)`来创建新...

    Spring3事务管理——使用@Transactional 注解.rar

    - `@Transactional`注解仅在Spring AOP代理能够拦截到的方法上生效,因此,如果在非Spring管理的类或静态方法中使用,事务管理将不起作用。 - 如果事务属性设置不当,可能会导致数据不一致或并发问题,应谨慎调整...

    Spring在Transaction事务传播行为种类

    事务传播行为是指当一个事务方法被另一个事务方法调用时,如何处理这些事务的方法。Spring通过`TransactionDefinition`接口定义了七种不同的事务传播行为类型,每一种都有其特定的用途和场景。了解这些事务传播行为...

    struct spring hibernate面试题

    当一个方法被标记为事务性的,Spring就会在该方法执行前后自动开启和提交/回滚事务,而无需在业务代码中显式编写事务管理代码。 #### 二、Hibernate框架面试题解析 **1. Hibernate为什么需要SessionFactory?** ...

Global site tag (gtag.js) - Google Analytics