浅析 Spring 声明式事务 @Transactional 源码

发表于 2023-02-04

技术基础

学习 Spring 声明式事务的源码还是需要一定的基础,学起来才更加容易。

  • 懂得 Spring 事务的使用,理解基本相关名词。
  • 有 Spring AOP 基础,最好阅读过 Spring AOP 源码并理解其解析、创建和调用相关流程。

Spring 版本

spring-framework-5.2.22.RELEASE

重点类介绍

我直接使用的是 Spring 项目源码,涉及到的 Spring 模块 spring-tx

  • EnableTransactionManagement
    • 使用注解 @EnableTransactionManagement 开启事务管理器。
  • TransactionManagementConfigurationSelector
    • 将事务相关组件注册成 Bean 定义。
  • AutoProxyRegistrar
    • 将解析切面(事务的切面)的 Bean 后置处理器注册成 Bean 定义。
  • ProxyTransactionManagementConfiguration
    • 声明事务的切面、通知、切点。
  • TransactionInterceptor
    • 用于处理事务的 AOP 通知
  • BeanFactoryTransactionAttributeSourceAdvisor
    • 事务的切面(包含切点、通知)
    • 由 TransactionAttributeSourcePointcut 持有 TransactionAttributeSource 用来匹配连接点
  • TransactionAttributeSource(实现:AnnotationTransactionAttributeSource)
    • 用于匹配查找事务注解
  • ConnectionHolder
    • 事务持有者,可以根据 ConnectionHolder 是否为 null 判断当前事务是否已开启事务。

用一句话描述事务的整体流程可以这样:事务就是依赖于 Spring AOP 创建一个切面,在切面中完成事务的相关管理功能。

还有一些工具类,就不过多介绍了,认识这些类后就可以逐步深入的阅读事务的相关源码了。

事务相关组件的注入

事务的组件在 重点类介绍 我都提到过了。这里讲一下整体的流程,并贴图一张。

  • 一般我在启动类使用注解 @EnableTransactionManagement 开启事务管理器,这就是事务的 入口
  • 在注解 @EnableTransactionManagement 中有 @Import(TransactionManagementConfigurationSelector.class)
  • 通过 @Import 解析类 TransactionManagementConfigurationSelector 后会注册两个 Bean 定义。
    • AutoProxyRegistrar 将会注册解析切面的 Bean 后置处理器。
    • ProxyTransactionManagementConfiguration 配置类使用 @Bean 配置了事务的 切面通知切点,它们将会在切面解析时创建。

Spring事务(切面)组件注册

解析事务并创建代理

事务的相关的切面是依赖于 Spring AOP 相关逻辑解析、创建。

  • 事务解析创建的 入口AutoProxyRegistrar 注册的 Bean 后置处理器:InfrastructureAdvisorAutoProxyCreator
  • InfrastructureAdvisorAutoProxyCreatorfindCandidateAdvisors() 方法查找实现了接口 Advisor 的切面。
  • 最后找到 Spring 事务的切面:BeanFactoryTransactionAttributeSourceAdvisor
  • TransactionAttributeSourcePointcut 调用 AnnotationTransactionAttributeSource 匹配符合条件的 连接点
    • 其方法 findTransactionAttribute 逐层调用直到 SpringTransactionAnnotationParser.parseTransactionAnnotation 查找注解 @Transactional
    • 根据当前 Bean 的所有方法,按顺序查找注解 @Transactional
    • 先根据方法没有会再次根据类查找,逻辑大致如下:
      • 当前方法 --> 接口方法 --> 父类方法
      • 当前类 --> 接口 --> 父类。
    • 细节涉及的核心工具类 AnnotationsScanner.sacn 扫描注解(还有递归,先接口、在父类)。
  • 为 Spring Bean 的事务创建代理。

解析事务并生成切面

事务的开启以及相关处理逻辑

调用逻辑仍然同 Spring AOP 一致,是一个切面被调用。

事务的相关逻辑在通知 TransactionInterceptorinvoke 方法开始事务的处理。

先不考虑事务嵌套的情况,主要理解单事务的情况,事务嵌套只是根据不同的 事务传播行为 切换事务的上下文。

  • invokeWithinTransaction 方法开始处理事务的相关逻辑,这是事务逻辑代码的入口。
  • 拿到事务的相关信息 TransactionAttributeSourceTransactionAttribute,在方法 createTransactionIfNecessary 开启事务()。
    • 判断是否存在事务(根据 ConnectionHolder 是否存在判断当前线程是否存在事务)。
    • 存在事务执行嵌套事务处理逻辑、不存在事务执行常规事务处理。
    • 挂起事务:将线程中的变量记录到 SuspendedResourcesHolder
    • 开启事务:获取数据库连接、创建 ConnectionHolder 记录到事务对象中。
  • 遇到异常进行事务的回滚(completeTransactionAfterThrowing)或者正常执行提交事务(commitTransactionAfterReturning)。

事务的开启以及相关处理逻辑