Spring AOP 与 事务实现

1. AOP 与方法调用

对于 接口 interface,可以通过 java.lang.reflect.Proxy 来生成动态代理对象;
对于 类 class,可以通过字节码技术,如 CBLIB 来生成一个子类作为代理对象,此时类不能声明为 final 。

当 Spring 把 Bean 注入到另一个 Bean 时,其实注入的是它生成的代理对象,进行方法调用时,首先调用的是代理对象上的方法,代理对象的方法最终再调目标对象的方法,也就是开发人员编写的方法。Spring 通过在调用目标方法前后做处理来实现一些特性,例如事务管理、缓存等。

Spring 的 AOP 是基于对代理对象的方法调用的拦截的,只能拦截外部对象 对 某个对象的方法的调用,对象的方法调用同一个类的方法是不会被拦截的。

@Service
public class SpringTxService {
    private static final Logger LOGGER = LoggerFactory
            .getLogger(SpringTxService.class);

    @Transactional(propagation = Propagation.REQUIRED)
    public void add() {
        LOGGER.info("do add");
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void requireNew() {
        LOGGER.info("do requireNew");
    }

    public void composite() {
        add();
        requireNew();
    }
}

上面的代码是基于注解进行事务控制的,composite 方法没有声明事务属性,它会调用 add、 requireNew
方法。当把 SpringTxService 注入到另一个 BeanB:
1. 在 BeanB 的方法里调用代理对象 composite 时,最终执行 add、 requireNew 是没有在事务里执行的,只是普通的方法调用。
2. 在 BeanB 的方法里调用代理对象的 add、 requireNew 方法时,这两个方法都会分别在相应的事务里执行。

当发现基于 AOP 实现的特性没有预期的效果时,一定要看看是不是在代理对象上调用还是目标类内部的方法调用。

2. 基于 JDBC 的 Spring 事务实现

代码逻辑在
org.springframework.transaction.support.AbstractPlatformTransactionManager 类的方法: private TransactionStatus handleExistingTransaction(TransactionDefinition definition, Object transaction, boolean debugEnabled) throws TransactionException;

  • PROPAGATION_REQUIRED

    特点: 如果当前线程关联了事务,则在当前事务里执行,否则新建一个事务。
    实现: 共用一个数据库连接、事务。

  • PROPAGATION_REQUIRES_NEW

    特点: 如果当前线程已关联了事务,则把当前事务挂起,然后创建一个新的事务,在新的事务里执行方法。
    实现: Spring 用 TransactionSynchronizationManager 持有一些 ThreadLocal 属性,用于保存当前线程所持有事务的属性。 把当前事务在 TransactionSynchronizationManager 里的属性保存起来,然后获取一个新的数据库连接,开启一个新的事务,这个新事物执行完后再恢复原有的事务。

  • PROPAGATION_NESTED

    特点: 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与 PROPAGATION_REQUIRED 类似的操作。
    实现: 通过在当前事务的 JDBC 连接上创建 SavePoint 来实现,这个 SavePoint 可以单独回滚,也可以跟外部事务一起回滚或提交,但不能单独提交。

  • PROPAGATION_NEVER

    特点: 如果当前线程关联了事务,则抛出 IllegalTransactionStateException 。
    实现: 检测到方法的事务属性是 PROPAGATION_NEVER 时,直接抛出异常。

  • PROPAGATION_SUPPORTS :

    特点: 支持当前事务,如果当前没有事务,就以非事务方式执行。
    实现: 其实是不需要做特殊处理。

  • PROPAGATION_NOT_SUPPORTED :

    特点: 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
    实现: 会把当前关联的事务挂起,然后继续执行,执行完后再恢复挂起的事务。


欢迎关注我的微信公众号: coderbee笔记,可以更及时回复你的讨论。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据