人人都能看懂的Spring源码解析,Spring声明式事务是如何实现的
人人都能看懂的Spring源码解析,Spring声明式事务是如何实现的
往期文章:
- 人人都能看懂的Spring底层原理,看完绝对不会懵逼
- 简单易懂的Spring扩展点详细解析,看不懂你来打我
- 人人都能看懂的Spring源码解析,配置解析与BeanDefinition加载注册
- 简单易懂又非常牛逼的Spring源码解析,ConfigurationClassPostProcessor的具体逻辑
- 简单易懂值得收藏的Spring源码解析,依赖注入和bean的初始化
- 人人都能看懂的Spring源码解析,Spring如何解决循环依赖
- 人人都能看懂的Spring源码解析,Spring如何处理AOP
原理解析
基本原理
事务的基本操作
事务的基本操作一共分为四步:
- 开启事务
- 在try块中执行业务逻辑
- 如果报错,在catch块中回滚事务
- 执行业务逻辑成功,提交事务

伪代码:
// 开启事务
try {
// 执行业务逻辑
} catch (Exception e) {
// 回滚事务
}
// 提交事务
编程式事务
要了解Spring声明式事务,首先要了解Spring编程式事务,因为Spring声明式事务是对编程式事务的简化,是基于编程式事务而来的。
Spring编程式事务有两种实现方式,一种是通过 TransactionManager(事务管理器) 实现,一种是通过 TransactionTemplate(事务模板) 实现。
通过 TransactionManager实现的编程式事务
@Autowired
private PlatformTransactionManager tm;
public void test() {
DefaultTransactionDefinition dte = new DefaultTransactionDefinition();
dte.setIsolationLevel(TransactionDefinition.ISOLATION_REPEATABLE_READ);
dte.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = tm.getTransaction(dte);
try {
doSomething();
} catch (RuntimeException e) {
tm.rollback(status);
}
tm.commit(status);
}
TransactionDefinition 是用于定义事务属性的接口,而DefaultTransactionDefinition 是它的默认实现类,可以设置事务的隔离级别和传播特性。
PlatformTransactionManager是Spring提供的事务管理器的接口,有getTransaction、commit、rollback三个方法,分别是开启事务并获取事务状态、提交事务、回滚事务。不同的ORM框架,可以实现该接口,就可以对接Spring事务。

通过TransactionTemplate实现的编程式事务
@Autowired
private PlatformTransactionManager tm;
public void test() {
TransactionTemplate tt = new TransactionTemplate(tm);
tt.setIsolationLevel(TransactionDefinition.ISOLATION_REPEATABLE_READ);
tt.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
tt.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
doSomething();
}
});
}
TransactionTemplate是事务模板类,用于简化基于TransactionManager的编程式事务。构造方法需要传递一个事务管理器TransactionManager。可见基于TransactionTemplate的编程式事务是对基于TransactionManager的编程式事务的封装。
TransactionTemplate同样可以设置事务的隔离级别和传播特性。
TransactionTemplate的execute方法是真正执行事务的方法,接收一个TransactionCallbackWithoutResult类型的参数,TransactionCallbackWithoutResult的doInTransactionWithoutResult方法里面写我们要执行的业务逻辑。而事务的开启、提交、回滚等代码不需要我们去写,Spring已经通过模板方法定义好了处理流程。
我们进入execute方法里面看一看:

可以看到就是典型的模板方法模式,包装了基于TransactionManager实现的编程式事务的代码流程,留了一个回调方法需要我们去实现,编写我们的业务逻辑。
声明式事务
声明式事务就是对编程式事务的简化,无需用户编写代码,又能使事务生效。
既然有了编程式事务的方式,声明式事务自然就不用重新搞一套API接口,可以复用编程式事务的接口,通过AOP的方式,实现对目标方法的增强,在增强逻辑中织入编程式事务的流程代码,就能达到无需用户编写代码,又能使事务生效的效果。

核心组件
要理解Spring声明式事务,除了要了解编程式事务以外,还要对使用到的组件有所了解。
Spring声明式事务使用到的组件包括:
- PlatformTransactionManager
- TransactionStatus
- TransactionDefinition
- TransactionAttribute
- TransactionInfo
- TransactionAttributeSource
- TransactionInterceptor
- BeanFactoryTransactionAttributeSourceAdvisor

PlatformTransactionManager
这个在上面已经介绍过,就是事务管理器接口,有开启事务(getTransaction)、提交事务(commit)、回滚事务(rollback)三个方法需要实现。
一般的调用流程如下:
- 通过PlatformTransactionManager#getTransaction方法开启事务
- 执行业务逻辑
- 如果业务逻辑报错,则调用PlatformTransactionManager#rollback方法回滚
- 如果业务逻辑执行成功,则调用PlatformTransactionManager#commit方法提交事务

TransactionStatus
TransactionStatus事务状态,用于记录事务的状态信息,比如是否是新事务、是否有回滚点、是否已完成等,PlatformTransactionManager#getTransaction方法会返回TransactionStatus对象,然后在调用PlatformTransactionManager#rollback方法或者PlatformTransactionManager#commit方法时要传递该对象。

TransactionDefinition
TransactionDefinition事务定义,用于定义事务属性,包括隔离级别和传播特性。PlatformTransactionManager#getTransaction方法需要接收TransactionDefinition类型的参数。

TransactionAttribute
TransactionAttribute事务属性,继承了TransactionDefinition接口,是TransactionDefinition的扩展接口,比如增加了**rollbackOn(Throwable ex)**方法,判断遇到给定的异常是否需要回滚。Spring声明式事务使用TransactionAttribute接口的实现类,作为PlatformTransactionManager#getTransaction方法的参数。

TransactionInfo
TransactionInfo事务信息,Spring声明式事务使用该对象把TransactionAttribute、TransactionStatus、PlatformTransactionManager等对象都封装到里面。

TransactionAttributeSource
TransactionAttributeSource事务属性源,通过它的getTransactionAttribute方法可以获取到事务属性TransactionAttribute。比如TransactionAttributeSource的实现类AnnotationTransactionAttributeSource就是解析方法上的@Transactional注解获取事务属性的。

TransactionInterceptor
TransactionInterceptor事务拦截器,封装了编程式事务的代码流程。当调用某个被@Transactional注解修饰的方法是,通过AOP机制拦截到方法的调用,就会调用TransactionInterceptor的invoke方法,进入到编程式事务的代码流程。

BeanFactoryTransactionAttributeSourceAdvisor
因为Spring声明式事务是基于Spring AOP实现的,自然要有自己的Advisor,这个Advisor就是BeanFactoryTransactionAttributeSourceAdvisor。BeanFactoryTransactionAttributeSourceAdvisor的Advice就是TransactionInterceptor;而Pointcut是TransactionAttributeSourcePointcut,会判断目标方法上是否有@Transactional注解修饰来确定是否要对目标方法做增强。

代码走读

@EnableTransactionManagement注解,引入了一个TransactionManagementConfigurationSelector。

TransactionManagementConfigurationSelector的selectImports方法,导入了两个类,一个是AutoProxyRegistrar,另一个是ProxyTransactionManagementConfiguration。



AutoProxyRegistrar实现了ImportBeanDefinitionRegistrar接口,registerBeanDefinition方法最后会注册一个InfrastructureAdvisorAutoProxyCreator,InfrastructureAdvisorAutoProxyCreator是AbstractAutoProxyCreator的子孙类。AbstractAutoProxyCreator的postProcessAfterInitialization方法是AOP处理的入口。


ProxyTransactionManagementConfiguration则是一个配置类。


可以看到导入了三个对象,BeanFactoryTransactionAttributeSourceAdvisor、TransactionAttributeSource、TransactionInterceptor。TransactionAttributeSource和TransactionInterceptor会设置到BeanFactoryTransactionAttributeSourceAdvisor里面。advisor.setAdvice(transactionInterceptor);表示BeanFactoryTransactionAttributeSourceAdvisor的advice是TransactionInterceptor,被@Transactional注解修饰的方法的调用,会被拦截,进入TransactionInterceptor的invoke方法。

BeanFactoryTransactionAttributeSourceAdvisor的Pointcut是TransactionAttributeSourcePointcut类型。TransactionAttributeSourcePointcut的matches方法判断是否要对目标方法做增强。






可以看到,如果目标方法上有@Transactional注解修饰,或者目标类上有@Transactional注解修饰,或者接口的方法上有@Transactional注解修饰,或者接口上有@Transactional注解修饰,那么就会解析@Transactional注解,生成AnnotationAttributes对象,判断能解析出AnnotationAttributes对象,matches方法返回true,就会对目标方法做增强。
而增强逻辑就是TransactionInterceptor的invoke方法。


TransactionInterceptor的invoke方法调用invokeWithinTransaction方法,invokeWithinTransaction方法里面就是一个try-catch。try前面调用了createTransactionIfNecessary方法开启事务;然后try块中调用invocation.proceedWithInvocation()执行目标方法;catch块中调用completeTransactionAfterThrowing判断是否需要回滚,如果需要则进行回滚;最后调用commitTransactionAfterReturning方法提交事务。

可以看到createTransactionIfNecessary里面就是调用了PlatformTransactionManager的getTransaction方法开启事务,然后把返回的TransactionStatus连同TransactionAttribute和PlatformTransactionManager一起封装到prepareTransactionInfo对象中。

completeTransactionAfterThrowing方法里面,判断TransactionAttribute对象不为空,并且TransactionAttribute的rollbackOn方法返回true,则调用PlatformTransactionManager的rollback方法回滚事务;否则调用PlatformTransactionManager的commit方法提交事务。

最后commitTransactionAfterReturning方法就是调用PlatformTransactionManager的commit方法提交事务。
总结
总的来说,Spring声明式事务就是通过AOP省去了编程式事务的代码,把编程式事务的模板代码抽到了增强逻辑中,不需要再让用户编程编程式事务的模板代码。
以下是对源码整体流程的总结:
- @EnableTransactionManagement注解引入TransactionManagementConfigurationSelector,TransactionManagementConfigurationSelector的的selectImports方法导入AutoProxyRegistrar和ProxyTransactionManagementConfiguration,AutoProxyRegistrar导入InfrastructureAdvisorAutoProxyCreator,ProxyTransactionManagementConfiguration导入了BeanFactoryTransactionAttributeSourceAdvisor、TransactionAttributeSource、TransactionInterceptor。
- BeanFactoryTransactionAttributeSourceAdvisor里面的TransactionAttributeSourcePointcut的matches方法,判断如果目标方法上有@Transactional注解修饰,或者目标类上有@Transactional注解修饰,或者接口的方法上有@Transactional注解修饰,或者接口上有@Transactional注解修饰,那么就会解析@Transactional注解,生成AnnotationAttributes对象,判断能解析出AnnotationAttributes对象,就会返回true,就会对目标方法做增强。
- TransactionInterceptor的invoke方法就是增强逻辑,封装了编程式事务的模板代码。TransactionInterceptor的invoke方法调用invokeWithinTransaction方法,invokeWithinTransaction方法里面先调用了createTransactionIfNecessary方法开启事务;然后在try块中调用invocation.proceedWithInvocation()执行目标方法;如果报错了,则在catch块中调用completeTransactionAfterThrowing判断是否需要回滚,如果需要则进行回滚;最后调用commitTransactionAfterReturning方法提交事务。
- createTransactionIfNecessary里面就是调用了PlatformTransactionManager的getTransaction方法开启事务。
- completeTransactionAfterThrowing方法里面,判断TransactionAttribute对象不为空,并且TransactionAttribute的rollbackOn方法返回true,则调用PlatformTransactionManager的rollback方法回滚事务;否则调用PlatformTransactionManager的commit方法提交事务。
- commitTransactionAfterReturning方法调用PlatformTransactionManager的commit方法提交事务。
其实面试中问到Spring事务相关的问题,一般是问一下Spring事务有哪几种隔离级别、传播特性,或者Spring事务什么情况下会失效等,很少会问到原理的。如果问到原理相关的问题,把Spring声明式事务的原理说到这里其实也差不多了,至于事务的传播特性是如何实现的、事务的挂起与恢复是如何实现的等细节问题,就留到下一篇文章再说吧。