【Spring】Spring5 事务源码分析
Spring声明式事务原理
@EnableTransactionManagement 注解向容器中添加AutoProxyRegistrar和ProxyTransactionManagementConfiguration组件,二者作用分别为:
- AutoProxyRegistrar:类似于AOP中的AspectJAutoProxyRegistrar,用于向容器中注册InfrastructureAdvisorAutoProxyCreator组件(类似于AOP里的自动代理器,一种后置处理器)来为普通组件进行代理包装,创建代理对象
- ProxyTransactionManagementConfiguration:用于注册事务增强器,该增强器内设置有事务拦截器,将在代理对象执行目标方法时进行拦截,并调用其
invoke()
方法,由事务管理器控制事务的提交与回滚。
Spring事务原理与AOP原理十分相似,都包含有后置处理器和拦截器思想,在组件创建后包装出代理对象、在代理对象执行目标方法时进行拦截,使用事务管理器控制事务的提交与回滚。
@EnableTransactionManagement
要开启事务管理,配置类中需要添加@EnableTransactionManagement。其通过 @Import 注解向容器中导入TransactionManagementConfigurationSelector。
TransactionManagementConfigurationSelector会根据adviceMode
的值(见上图黄色框),选择导入什么类型的组件。默认导入:
- AutoProxyRegistrar:类似于AOP中的AspectJAutoProxyRegistrar,用于向容器中注册InfrastructureAdvisorAutoProxyCreator组件(类似于AOP里的自动代理器,一种后置处理器)来为普通组件进行代理包装,创建代理对象
- ProxyTransactionManagementConfiguration:用于注册事务增强器,该增强器内设置有事务拦截器,将在代理对象执行目标方法时进行拦截,并调用其
invoke()
方法,由事务管理器控制事务的提交与回滚。
下面分别介绍AutoProxyRegistrar和ProxyTransactionManagementConfiguration的作用。
AutoProxyRegistrar
AutoProxyRegistrar的作用类似于AOP中使用到的AspectJAutoProxyRegistrar。二者都能向容器中注册一个自动代理创建器的定义(见黄色框)
- AutoProxyRegistrar:注册InfrastructureAdvisorAutoProxyCreator(基础的自动代理器)
- AspectJAutoProxyRegistrar:注册AnnotationAwareAspectJAutoProxyCreator(注解装配模式的自动代理器)
二者注册的自动代理创建器都实现了SmartInstantiationAwareBeanPostProcessor接口和BeanFactoryAware接口,因此都是一种特殊的后置处理器。
InfrastructureAdvisorAutoProxyCreator
它实现了SmartInstantiationAwareBeanPostProcessor接口和BeanFactoryAware接口,是一种特殊的后置处理器。它的作用和AnnotationAwareAspectJAutoProxyCreator相似,都会在普通组件创建前后进行拦截,调用后置处理器的postProcessAfterInitialization()
方法,将普通组件进行包装(wrap),为其创建一个代理对象(其内含有相应的增强器)。该代理对象在执行目标方法时,会被事务拦截器所拦截,并由事务管理器控制事务的提交与回滚。
ProxyTransactionManagementConfiguration
ProxyTransactionManagementConfiguration被@Configuration
修饰,是一个配置类。它会给容器中注册一个事务增强器 BeanFactoryTransactionAttributeSourceAdvisor。该增强器需要设置两个对象:
- 事务注解属性解析器 TransactionAttributeSource:用以解析事务注解里设置的属性值。
- 事务拦截器 TransactionInterceptor:是一种
MethodInterceptor
。其内保存了事务属性信息,事务管理器。在代理对象执行目标方法时被其拦截,并调用invoke()
方法,由事务管理器控制事务的提交与回滚。
事务拦截器和事务注解属性解析器:
TransactionAttributeSource
事务注解属性解析器:TransactionAttributeSource,该组件同样在当前配置类中注册,其作用是解析 @Transactional() 注解里设置的属性值:
TransactionInterceptor
事务拦截器:TransactionInterceptor,是一种MethodInterceptor
方法拦截器,其会在代理对象执行目标方法时进行拦截(工作时机类似于AOP中的各种增强器拦截器),并执行其invoke()
方法(拦截器功能的执行都是通过invoke()
方法):
进入该方法内:
- 使用
TransactionAttributeSource
组件获取@Transactional()
注解里设置的相关属性 - 获取事务管理器
PlatformTransactionManager
组件(若事先没有手动添加任何事务管理器,则会从容器中获取在配置类中注册的PlatformTransactionManager
)
获取PlatformTransactionManager
组件的方法:
- 在代理对象执行目标方法时,使用
try catch
包裹业务代码,若出现异常可捕获并进行回滚(并将该异常再次抛出),若没有异常则提交事务:
其中createTransactionIfNecessary()
方法将创建一个事务的状态信息txInfo
(上图第一行),其内保存了事务的信息和事务管理器:
返回的TransactionInfo对象中保存了当前事务的状态信息(包含事务注解里的信息,例如传播特性;事务管理器等),后文将使用该对象获取到事务管理器执行事务的提交和回滚:
若发生异常,则使用事务管理器进行回滚,该事务管理器从上文中的TransactionInfo中获取(黄色框中回滚时从txInfo中获取到了事务的状态):
若没有发生异常,则使用事务管理器提交事务(黄色框中提交时从txInfo中获取到了事务的状态):
事务和线程的关系
当一个新的事务创建时,就会被绑定到当前线程上。
TransactionAspectSupport类中的ThreadLocal<TransactionInfo>
在当前线程保存了一个事务的信息TransactionInfo:
该线程会伴随着这个事务整个生命周期,直到事务提交、回滚或挂起(临时解绑)时该线程才会取消与该事务的绑定。
同时一个线程只能绑定一个事务,若当前线程原本正绑定的事务还未执行完毕就被新的事务所挂起,则该线程与该事务进行临时解绑,并绑定到新创建的事务上;直到新建的事务提交或回滚后,该线程才会结束与该新建事务的绑定,再次重新绑定之前的事务。
上述过程实现的原理为使用链表结构:创建一张TransactionInfo
链表,将新创建的事务TransactionInfo
链接到旧的事务TransactionInfo
的尾部,待新事务执行完毕后再指回旧的事务TransactionInfo
:
当新创建的事务结束时恢复旧的事务状态:
什么是事务挂起,如何实现挂起
对事务的配置在Spring内部会被封装成TransactionInfo,线程绑定了事务,自然也绑定了事务相关的TransactionInfo。挂起事务时,把TransactionInfo取出临时存储,等待执行完成后,把之前临时存储的TransactionInfo重新绑定到该线程上。
关于事务挂起的举例:(某事务挂起之后,任何操作都不在该事务的控制之下)
例如: 方法A支持事务,方法B不支持事务,即PROPAGATION_NOT_SUPPORTED
。方法A调用方法B:
- 在方法A开始运行时,系统为它建立Transaction,方法A中对于数据库的处理操作,会在该Transaction的控制之下。
- 这时,方法A调用方法B,方法A打开的Transaction将挂起,方法B中任何数据库操作,都不在该Transaction的管理之下。
- 当方法B返回,方法A继续运行,之前的Transaction恢复,后面的数据库操作继续在该Transaction的控制之下提交或回滚。