人人都能看懂的Spring源码解析,Spring声明式事务是如何实现的

往期文章:

  1. 人人都能看懂的Spring底层原理,看完绝对不会懵逼
  2. 简单易懂的Spring扩展点详细解析,看不懂你来打我
  3. 人人都能看懂的Spring源码解析,配置解析与BeanDefinition加载注册
  4. 简单易懂又非常牛逼的Spring源码解析,ConfigurationClassPostProcessor的具体逻辑
  5. 简单易懂值得收藏的Spring源码解析,依赖注入和bean的初始化
  6. 人人都能看懂的Spring源码解析,Spring如何解决循环依赖
  7. 人人都能看懂的Spring源码解析,Spring如何处理AOP

原理解析

基本原理

事务的基本操作

事务的基本操作一共分为四步

  1. 开启事务
  2. 在try块中执行业务逻辑
  3. 如果报错,在catch块中回滚事务
  4. 执行业务逻辑成功,提交事务

在这里插入图片描述

伪代码

// 开启事务
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提供的事务管理器的接口,有getTransactioncommitrollback三个方法,分别是开启事务并获取事务状态、提交事务、回滚事务。不同的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)三个方法需要实现。

一般的调用流程如下:

  1. 通过PlatformTransactionManager#getTransaction方法开启事务
  2. 执行业务逻辑
  3. 如果业务逻辑报错,则调用PlatformTransactionManager#rollback方法回滚
  4. 如果业务逻辑执行成功,则调用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省去了编程式事务的代码,把编程式事务的模板代码抽到了增强逻辑中,不需要再让用户编程编程式事务的模板代码。

以下是对源码整体流程的总结:

  1. @EnableTransactionManagement注解引入TransactionManagementConfigurationSelector,TransactionManagementConfigurationSelector的的selectImports方法导入AutoProxyRegistrar和ProxyTransactionManagementConfiguration,AutoProxyRegistrar导入InfrastructureAdvisorAutoProxyCreator,ProxyTransactionManagementConfiguration导入了BeanFactoryTransactionAttributeSourceAdvisor、TransactionAttributeSource、TransactionInterceptor。
  2. BeanFactoryTransactionAttributeSourceAdvisor里面的TransactionAttributeSourcePointcut的matches方法,判断如果目标方法上有@Transactional注解修饰,或者目标类上有@Transactional注解修饰,或者接口的方法上有@Transactional注解修饰,或者接口上有@Transactional注解修饰,那么就会解析@Transactional注解,生成AnnotationAttributes对象,判断能解析出AnnotationAttributes对象,就会返回true,就会对目标方法做增强。
  3. TransactionInterceptor的invoke方法就是增强逻辑,封装了编程式事务的模板代码。TransactionInterceptor的invoke方法调用invokeWithinTransaction方法,invokeWithinTransaction方法里面先调用了createTransactionIfNecessary方法开启事务;然后在try块中调用invocation.proceedWithInvocation()执行目标方法;如果报错了,则在catch块中调用completeTransactionAfterThrowing判断是否需要回滚,如果需要则进行回滚;最后调用commitTransactionAfterReturning方法提交事务。
  4. createTransactionIfNecessary里面就是调用了PlatformTransactionManager的getTransaction方法开启事务。
  5. completeTransactionAfterThrowing方法里面,判断TransactionAttribute对象不为空,并且TransactionAttribute的rollbackOn方法返回true,则调用PlatformTransactionManager的rollback方法回滚事务;否则调用PlatformTransactionManager的commit方法提交事务。
  6. commitTransactionAfterReturning方法调用PlatformTransactionManager的commit方法提交事务。

其实面试中问到Spring事务相关的问题,一般是问一下Spring事务有哪几种隔离级别、传播特性,或者Spring事务什么情况下会失效等,很少会问到原理的。如果问到原理相关的问题,把Spring声明式事务的原理说到这里其实也差不多了,至于事务的传播特性是如何实现的、事务的挂起与恢复是如何实现的等细节问题,就留到下一篇文章再说吧。