【Spring】Spring5 事务源码分析

Spring声明式事务原理

@EnableTransactionManagement 注解向容器中添加AutoProxyRegistrarProxyTransactionManagementConfiguration组件,二者作用分别为:

  • AutoProxyRegistrar:类似于AOP中的AspectJAutoProxyRegistrar,用于向容器中注册InfrastructureAdvisorAutoProxyCreator组件(类似于AOP里的自动代理器,一种后置处理器)来为普通组件进行代理包装,创建代理对象
  • ProxyTransactionManagementConfiguration:用于注册事务增强器,该增强器内设置有事务拦截器,将在代理对象执行目标方法时进行拦截,并调用其invoke()方法,由事务管理器控制事务的提交与回滚

Spring事务原理与AOP原理十分相似,都包含有后置处理器拦截器思想,在组件创建后包装出代理对象、在代理对象执行目标方法时进行拦截,使用事务管理器控制事务的提交与回滚。

@EnableTransactionManagement

要开启事务管理,配置类中需要添加@EnableTransactionManagement。其通过 @Import 注解向容器中导入TransactionManagementConfigurationSelector

image-20210705162841045

TransactionManagementConfigurationSelector会根据adviceMode的值(见上图黄色框),选择导入什么类型的组件。默认导入:

  • AutoProxyRegistrar:类似于AOP中的AspectJAutoProxyRegistrar,用于向容器中注册InfrastructureAdvisorAutoProxyCreator组件(类似于AOP里的自动代理器,一种后置处理器)来为普通组件进行代理包装,创建代理对象
  • ProxyTransactionManagementConfiguration:用于注册事务增强器,该增强器内设置有事务拦截器,将在代理对象执行目标方法时进行拦截,并调用其invoke()方法,由事务管理器控制事务的提交与回滚

image-20210705162739312

下面分别介绍AutoProxyRegistrarProxyTransactionManagementConfiguration的作用。

AutoProxyRegistrar

AutoProxyRegistrar的作用类似于AOP中使用到的AspectJAutoProxyRegistrar。二者都能向容器中注册一个自动代理创建器的定义(见黄色框)

  • AutoProxyRegistrar:注册InfrastructureAdvisorAutoProxyCreator(基础的自动代理器)
  • AspectJAutoProxyRegistrar:注册AnnotationAwareAspectJAutoProxyCreator(注解装配模式的自动代理器)

二者注册的自动代理创建器都实现了SmartInstantiationAwareBeanPostProcessor接口和BeanFactoryAware接口,因此都是一种特殊的后置处理器

image-20210705165313341

image-20210705165700051

InfrastructureAdvisorAutoProxyCreator

它实现了SmartInstantiationAwareBeanPostProcessor接口和BeanFactoryAware接口,是一种特殊的后置处理器。它的作用和AnnotationAwareAspectJAutoProxyCreator相似,都会在普通组件创建前后进行拦截,调用后置处理器的postProcessAfterInitialization()方法,将普通组件进行包装(wrap),为其创建一个代理对象(其内含有相应的增强器)。该代理对象在执行目标方法时,会被事务拦截器所拦截,并由事务管理器控制事务的提交与回滚。

image-20210705175257029

ProxyTransactionManagementConfiguration

ProxyTransactionManagementConfiguration@Configuration修饰,是一个配置类。它会给容器中注册一个事务增强器 BeanFactoryTransactionAttributeSourceAdvisor。该增强器需要设置两个对象:

  • 事务注解属性解析器 TransactionAttributeSource:用以解析事务注解里设置的属性值。
  • 事务拦截器 TransactionInterceptor:是一种MethodInterceptor。其内保存了事务属性信息,事务管理器。在代理对象执行目标方法时被其拦截,并调用invoke()方法,由事务管理器控制事务的提交与回滚

image-20210705180105446

事务拦截器和事务注解属性解析器:

image-20210705192545675

TransactionAttributeSource

事务注解属性解析器:TransactionAttributeSource,该组件同样在当前配置类中注册,其作用是解析 @Transactional() 注解里设置的属性值:

image-20210705180534636

TransactionInterceptor

事务拦截器:TransactionInterceptor,是一种MethodInterceptor方法拦截器,其会在代理对象执行目标方法时进行拦截(工作时机类似于AOP中的各种增强器拦截器),并执行其invoke()方法(拦截器功能的执行都是通过invoke()方法):

image-20210705192758666

image-20210705195121588

进入该方法内:

  1. 使用TransactionAttributeSource组件获取@Transactional()注解里设置的相关属性
  2. 获取事务管理器PlatformTransactionManager组件(若事先没有手动添加任何事务管理器,则会从容器中获取在配置类中注册的PlatformTransactionManager

获取PlatformTransactionManager组件的方法:

image-20210705193959819

  1. 在代理对象执行目标方法时,使用try catch包裹业务代码,若出现异常可捕获并进行回滚(并将该异常再次抛出),若没有异常则提交事务:

image-20210818102456796

其中createTransactionIfNecessary()方法将创建一个事务的状态信息txInfo(上图第一行),其内保存了事务的信息和事务管理器

image-20210816221209341

返回的TransactionInfo对象中保存了当前事务的状态信息(包含事务注解里的信息,例如传播特性;事务管理器等),后文将使用该对象获取到事务管理器执行事务的提交和回滚:

若发生异常,则使用事务管理器进行回滚,该事务管理器从上文中的TransactionInfo中获取(黄色框中回滚时从txInfo中获取到了事务的状态):

image-20210705195609111

若没有发生异常,则使用事务管理器提交事务(黄色框中提交时从txInfo中获取到了事务的状态):

image-20210705195711824

事务和线程的关系

当一个新的事务创建时,就会被绑定到当前线程上

TransactionAspectSupport类中的ThreadLocal<TransactionInfo>在当前线程保存了一个事务的信息TransactionInfo

image-20210818103221467

该线程会伴随着这个事务整个生命周期,直到事务提交、回滚或挂起(临时解绑)时该线程才会取消与该事务的绑定。

同时一个线程只能绑定一个事务,若当前线程原本正绑定的事务还未执行完毕就被新的事务所挂起,则该线程与该事务进行临时解绑,并绑定到新创建的事务上;直到新建的事务提交或回滚后,该线程才会结束与该新建事务的绑定,再次重新绑定之前的事务。

上述过程实现的原理为使用链表结构:创建一张TransactionInfo链表,将新创建的事务TransactionInfo链接到旧的事务TransactionInfo的尾部,待新事务执行完毕后再指回旧的事务TransactionInfo

image-20210818104726262

image-20210818105411421

当新创建的事务结束时恢复旧的事务状态:

image-20210818105517020

什么是事务挂起,如何实现挂起

对事务的配置在Spring内部会被封装成TransactionInfo,线程绑定了事务,自然也绑定了事务相关的TransactionInfo挂起事务时,把TransactionInfo取出临时存储,等待执行完成后,把之前临时存储的TransactionInfo重新绑定到该线程上

关于事务挂起的举例:(某事务挂起之后,任何操作都不在该事务的控制之下)

https://blog.csdn.net/xiaoshuo566/article/details/83929465

例如: 方法A支持事务,方法B不支持事务,即PROPAGATION_NOT_SUPPORTED。方法A调用方法B:

  • 在方法A开始运行时,系统为它建立Transaction,方法A中对于数据库的处理操作,会在该Transaction的控制之下。
  • 这时,方法A调用方法B,方法A打开的Transaction将挂起,方法B中任何数据库操作,都不在该Transaction的管理之下。
  • 当方法B返回,方法A继续运行,之前的Transaction恢复,后面的数据库操作继续在该Transaction的控制之下提交或回滚。