Spring事务机制实现原理
小橘子🍊

前言

在我的上一篇文章中已经比较详细的对 Spring 的 AOP 实现原理进行了说明,而 Spring 的事务实现原理呢又跟 Spring 的 AOP 实现有着较大的关系,所以这里选择成热打铁,对 Spring 的事务实现机制进行一下说明。上一篇文章在对 AOP 实现进行解释时,只分析了它的 cglib 代理实现,因为提供的例子中被代理类没有实现相应的接口,导致不能通过 jdk 原生方式进行代理,而本文将要解释的 Spring 事务实现中,例子是实现了用户服务接口的,所以代理方式是采用的 jdk 原生方式,正好能够对上文进行补充。同样的示例代码我已经提交到我的 github 上,欢迎自取。在阅读本文之前,十分的建议先看我的上一篇 Spring AOP 实现原理文章,因为分析 Spring 事务实现原理的方式和分析 Spring AOP 实现原理的方式十分相似,如果对上一篇文章理解得好,Spring 的事务实现完全可以按照同样的方式来进行分析。

示例程序

实例程序很简单,已经同步到上文 github 链接上了,在 spring-example 模块的 top.aprilyolies.example.tx 包之下,执行前还需要先在数据库中创建数据表,sql 文件在当前模块下的 db 文件夹下。

主函数 top.aprilyolies.example.tx.TxApp

1
2
3
4
5
6
7
8
9
10
11
public class TxApp {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-tx.xml");
UserService userService = (UserService) context.getBean("userService");
User user = new User();
user.setSex("man");
user.setName("eva");
user.setAge(23);
userService.save(user);
}
}

pojo 类省略 getter 和 setter 方法 top.aprilyolies.example.tx.User

1
2
3
4
5
6
public class User {
private int id;
private String name;
private int age;
private String sex;
}

top.aprilyolies.example.tx.UserRowMapper

1
2
3
4
5
6
7
8
9
10
11
public class UserRowMapper implements RowMapper {
@Override
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User();
user.setAge(rs.getInt("age"));
user.setId(rs.getInt("id"));
user.setName(rs.getString("name"));
user.setSex(rs.getString("sex"));
return user;
}
}

top.aprilyolies.example.tx.UserService

1
2
3
public interface UserService {
void save(User user);
}

top.aprilyolies.example.tx.UserServiceImpl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Transactional
public class UserServiceImpl implements UserService {
private JdbcTemplate template = new JdbcTemplate();

public void setDataSource(DataSource dataSource) {
this.template.setDataSource(dataSource);
}

@Override
public void save(User user) {
template.update("insert into user(name,age,sex) values (?,?,?)", user.getName(), user.getAge(), user.getSex());
throw new RuntimeException("Test tx");
}
}

top.aprilyolies.example.tx.UserService

1
2
3
public interface UserService {
void save(User user);
}

spring-tx.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

<tx:annotation-driven/>

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 关联数据源 -->
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 基于Druid数据库链接池的数据源配置 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="clone">
<!-- 基本属性driverClassName、 url、user、password -->
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/common"/>
<property name="username" value="root"/>
<property name="password" value="kuaile1.."/>
</bean>

<bean id="userService" class="top.aprilyolies.example.tx.UserServiceImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>

执行主函数,会发现程序抛出运行时异常,查看数据库可以看到我们准备插入的数据没有出现。如果我们将 top.aprilyolies.example.tx.UserServiceImpl 类的 @Transactional 注解去掉,再执行主函数,这时可以看到程序同样是抛出了运行时异常,但是当前这条记录却被插入了数据库中。

解释就是当我们使用 @Transactional 注解时,那么 spring 在执行对应的方法时会开启事务,这样如果在事务中 java 程序出现异常,spring 就会自动完成事务的回滚。当把 @Transactional 注解去掉后,我们就是执行的普通方法,这样默认的事务机制是自动提交,当执行完 template.update 方法时,记录已经进入数据库,此时再抛出异常,将不会对结果产生影响。当然这只是直观的感受,具体的实现还是要看源码,本文的主要内容也就是这个。

标签解析

在我们的 spring 配置文件中只有一个特殊标签 <tx:annotation-driven/>,根据上文中的介绍,我们直接定位到 TxNamespaceHandler#init 方法如下,很明显这里应该关注 <tx:annotation-driven/> 标签对应的 AnnotationDrivenBeanDefinitionParser。

1
2
3
4
5
6
@Override
public void init() {
registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
}

AnnotationDrivenBeanDefinitionParser 类实现了 BeanDefinitionParser 接口,直接看接口的 parse 方法实现。第一行代码就是向 spring 容器注册了一个 TransactionalEventListenerFactory 相关的 bean,这个 bean 的作用暂时没有深究。接下来就是一个 if-else 分支,也就是说 spring 的事务实现有两种模式,如果在 <tx:annotation-driven/> 标签中指定了 mode 属性为 “aspectj”,那么就会实现 aspectj 模式的事务机制,否则就是通过代理的方式实现事务,当然 spring 默认情况下就是采用的代理方式来实现事务处理,这也就是开篇说 Spring 事务机制跟 Spring AOP 实现原理有关的原因。aspectj 模式这里没做深入的了解,以后如果用上了就再看。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public BeanDefinition parse(Element element, ParserContext parserContext) {
registerTransactionalEventListenerFactory(parserContext); // 根本就是向 spring 容器注册了一个 TransactionalEventListenerFactory 相关的 bean
String mode = element.getAttribute("mode"); // 默认是通过 proxy 的方式
if ("aspectj".equals(mode)) { // 这里说明事务支持的实现有两种方式,aspectj 和 proxy 的方式
// mode="aspectj" // 这种模式没接触过,暂不了解
registerTransactionAspect(element, parserContext);
if (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader())) {
registerJtaTransactionAspect(element, parserContext);
}
}
else {// 主要是向 spring 容器注册了四个 BeanDefinition,包括 AnnotationTransactionAttributeSource、TransactionInterceptor、BeanFactoryTransactionAttributeSourceAdvisor
// mode="proxy" 以及 CompositeComponentDefinition,都完成了一些属性的设置
AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
}
return null;
}

直接看 else 分支,它就是调用了 AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext); 方法,里边的实现其实就是跟 Spring AOP 的实现一样的套路,代码如下,不过这里注册的 bean 稍多,有五个包括 InfrastructureAdvisorAutoProxyCreator(实现了 SmartInstantiationAwareBeanPostProcessor 接口,负责代理类的生成)、AnnotationTransactionAttributeSource(主要是用来存储一些事务相关的属性信息)、TransactionInterceptor(事务实现的核心拦截器,事务的回滚都是在其中完成)、BeanFactoryTransactionAttributeSourceAdvisor(增强器)
以及 CompositeComponentDefinition(上述三种 bean 的组合)。请留意这些 bean,因为在后边的事务实现中,除了最后一个组合 bean,均有涉及到。还有就是要注意这句代码 advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);,advisorDef 代表的就是 BeanFactoryTransactionAttributeSourceAdvisor 类对应的 BeanDefinition,而 interceptorName 就是 TransactionInterceptor 实例在 spring 容器中的唯一标识符,当执行完这条代码后,那么 advisor 就算是持有了 TransactionInterceptor 的唯一标识符了,也就能够间接的获取到 spring 容器中的 TransactionInterceptor 实例了。
interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName)); 这句代码的作用同理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
// 核心就是注册了 InfrastructureAdvisorAutoProxyCreator 对应的 bean,并设置了它创建代理的方式
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME; // 和事务相关的增强器唯一标识符
if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {
Object eleSource = parserContext.extractSource(element);

// Create the TransactionAttributeSource definition.
RootBeanDefinition sourceDef = new RootBeanDefinition( // 这一部分就是创建一个 RootBeanDefinition,持有了 eleSource,角色为 ROLE_INFRASTRUCTURE,并进行了注册
"org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
sourceDef.setSource(eleSource);
sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);

// Create the TransactionInterceptor definition. // TransactionInterceptor 实现了 MethodInterceptor 接口,说明它可以被当做方法拦截器使用
RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class); // 这一部分就是创建了一个 TransactionInterceptor 对应的 RootBeanDefinition
interceptorDef.setSource(eleSource); // 持有了 eleSource,角色为 ROLE_INFRASTRUCTURE
interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registerTransactionManager(element, interceptorDef); // 为当前 BeanDefinition 添加了一个 transactionManagerBeanName 属性
interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName)); // 为当前 BeanDefinition 添加了一个 transactionAttributeSource 属性
String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef); // 注册当前的 RootBeanDefinition

// Create the TransactionAttributeSourceAdvisor definition. // Advisor 后缀,猜测它能当做增强使用
RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class); // 构建 BeanFactoryTransactionAttributeSourceAdvisor 对应的 RootBeanDefinition
advisorDef.setSource(eleSource);
advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName)); // 指定了 transactionAttributeSource 和 adviceBeanName 属性
advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
if (element.hasAttribute("order")) {
advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
}
parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);

CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);
compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName));
compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName));
compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, txAdvisorBeanName));
parserContext.registerComponent(compositeDef);
}
}

到这里 <tx:annotation-driven/> 标签的解析过程就算完成了,总结下来就是注册了一个 TransactionalEventListenerFactory,然后根据标签属性来确定事务的实现模式是 aspectj 还是 proxy,如果是 proxy 方式,那么就是向 spring 容器中注册了上述的五个 bean。

构建事务代理类

上文已经提到了在 <tx:annotation-driven/> 标签的解析过程中会向 spring 容器注册五个类型的 bean,我这里再罗列一下,因为事务代理类的构建和事务机制的实现都和前四个类型的 bean 息息相关,关于他们的作用我都进行了说明,其中第一个 bean 就是用来构建事务代理类的,它的实现模式跟 spring aop 基本一致。

  • InfrastructureAdvisorAutoProxyCreator(实现了 SmartInstantiationAwareBeanPostProcessor 接口,负责代理类的生成)

  • AnnotationTransactionAttributeSource(主要是用来存储一些事务相关的属性信息)

  • TransactionInterceptor(事务实现的核心拦截器,事务的回滚都是在其中完成)

  • BeanFactoryTransactionAttributeSourceAdvisor(增强器)

  • CompositeComponentDefinition(上述三种 bean 的组合)

InfrastructureAdvisorAutoProxyCreator 实现了 SmartInstantiationAwareBeanPostProcessor 接口,按照上一篇文章所说的,我们直接关注到事务代理类创建的方法如下:

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization

1
2
3
4
5
6
7
8
9
10
@Override	// 尝试从缓存中获取代理 bean,没有的话进行构建,核心就是构建 enhancer,根据 enhancer 构建代理类 class,然后通过 class 构建代理类实例,最后将 callbacks 设置到其中
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
return wrapIfNecessary(bean, beanName, cacheKey); // 核心就是构建 enhancer,根据 enhancer 构建代理类 class,然后通过 class 构建代理类实例,最后将 callbacks 设置到其中
}
}
return bean;
}

这部分代码在上一篇文章中已经说过了,所以不再赘述,但是在 wrapIfNecessary 方法的实现中,和 spring aop 原理分析中的样例代码不一样,这里通过 getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null); 获取到的 specificInterceptors 只有一个如下图所示,这个跟 spring aop 原理分析文章中得到的和 @Before、@After、@Around 三个注解代表的 Advisor 相对应。好了自己看看现在获取到的这个 Advisor 的类型,是不是很熟悉呢??没错这个 advisor 就是上文中提出的那个五个 bean 当中的一个。

本例中唯一的 Advisor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 判断是否需要代理,如果是,获取满足 beanClass 的 advisor,然后构建代理类:验证代理工厂长持有的目标类,然后构建 enhancer,根据 enhancer 构建代理类 class,然后通过 class 构建代理类实例,最后将 callbacks 设置到其中
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean; // 无需代理,直接返回
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean; // 基础类和应跳过的类直接返回
}

// Create proxy if we have advice. // 获取满足 beanClass 的 advisor,进行过排序
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE); // 所以这个集合存放的是对应的 bean 是否增强的信息
Object proxy = createProxy( // 验证代理工厂长持有的目标类,然后构建 enhancer,根据 enhancer 构建代理类 class,然后通过 class 构建代理类实例,最后将 callbacks 设置到其中
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
// 所以这个集合存放的是对应的 bean 是否增强的信息
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}

拿到这个 advisor 后就是构建代理类,上篇文章中走的是 cglib 代理分支,而现在走的是 jdk 代理方式的分支,判断的逻辑是由下边代码的 evaluateProxyInterfaces(beanClass, proxyFactory); 这一行所决定的,该行代码会看目标 class 是否有可以代理的接口,有的话将接口 class 添加到 proxyFactory 中,否则设置代理方式为代理目标类即 cglib 的方式。因为我们的目标类是 UserServiceImpl,它实现了 UserService 接口,因此是满足 jdk 动态代理条件的。另外需要注意的是下边的方法通过参数传入的 specificInterceptors 被转换为了 Advisor,它又被传入了 proxyFactory 中,所以 proxyFactory 是持有了我们 Advisor 的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
@Nullable Object[] specificInterceptors, TargetSource targetSource) { // TargetSource 封装了我们的目标实例

if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}

ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this); // 当前类的属性复制到 ProxyFactory 中

if (!proxyFactory.isProxyTargetClass()) { // 这里就是判断代理目标类还是接口分别对应 cglib 和 jdk 代理方式
if (shouldProxyTargetClass(beanClass, beanName)) { // 看是否属性值指定了 org.springframework.aop.framework.autoproxy.AutoProxyUtils.preserveTargetClass,这种情况采用目标类代理方式 cglib
proxyFactory.setProxyTargetClass(true); // 这里设置代理方式为 cglib
}
else { // 看目标 class 是否有可以代理的接口,有的话将接口 class 添加到 proxyFactory 中,否则设置代理方式为代理目标类
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
// 获取公有的 interceptors,然后和 specificInterceptors 一起构建为 advisors 返回
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource); // 这个参数持有了代理目标
customizeProxyFactory(proxyFactory);

proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) { // advisors 预过滤
proxyFactory.setPreFiltered(true);
}
// 验证代理工厂长持有的目标类,然后构建 enhancer,根据 enhancer 构建代理类 class,然后通过 class 构建代理类实例,最后将 callbacks 设置到其中
return proxyFactory.getProxy(getProxyClassLoader());
}

知道要采用 jdk 动态代理的方式后,我们就细看这个代理类是如何构建的,对应的 InvocationHandler 又是怎样的,之所以关注 InvocationHandler,是因为 jdk 代理类的根本逻辑还是调用 InvocationHandler 实例的 invoke 方法。我们直接看上边代码块的最后一句即 return proxyFactory.getProxy(getProxyClassLoader()); 。它的实现如下 :

1
2
3
4
// 创建代理类
public Object getProxy(@Nullable ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader); // jdk:获取必须的接口信息,构建代理类,invocation handler 就是 JdkDynamicAopProxy 实例
} // cglib:验证代理工厂长持有的目标类,然后构建 enhancer,根据 enhancer 构建代理类 class,然后通过 class 构建代理类实例,最后将 callbacks 设置到其中

逻辑跟 aop 实现的分析是一样的,第一段代码执行的结果可以算作是一个工厂类,通过下边的代码我们知道拿到的是一个 JdkDynamicAopProxy 实例,然后我们调用它的 getProxy 方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass(); // 执行到这里,说明采用 cglib 代理方式
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
} // 目标类是接口或者是 Proxy 接口实现类,那么进行 jdk 代理
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config); // 这里就是进行 jdk 代理方式
}
}

下边就是 JdkDynamicAopProxy#getProxy(java.lang.ClassLoader) 方法的实现,熟悉 jdk 动态代理的小伙伴应该立即就能知道这是一个典型的通过 Proxy 类创建 jdk 代理类的过程。其中 proxiedInterfaces 参数代表着创建的代理类需要实现的接口类型。而紧跟的那个参数 this 其实就是 InvocationHandler 实例了。如果我们执行代理类的方法,那么该实例的 invoke 方法将会被调用,这是本文下一部分将要分析的内容。

记住这里的 this 代表着 JdkDynamicAopProxy 类,可以肯定它实现了 InvocationHandler 接口,而且它持有了 ProxyFactory 实例,上文我们指出过 ProxyFactory 又持有了本例中唯一的 Advisor,所以可以说我们的 InvocationHandler 也是间接的持有了这个唯一的 Advisor。

proxiedInterfaces 是一个数组类型,这就说明我们的代理类可以实现多个接口,就拿本例来说,我把所有的接口类型贴在下边,可以看到我们最关心的 UserService 接口就在其中,至于其它的几个接口怎么来的请自行查看 AopProxyUtils.completeProxiedInterfaces(this.advised, true); 方法的实现。

1
2
3
4
5
6
7
8
9
@Override	// 获取必须的接口信息,构建代理类,invocation handler 就是 JdkDynamicAopProxy 实例
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
} // 获取全部的代理接口集合,包括 advised 中获取的全部接口集合以及制定的三个接口
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces); // 看接口中是否定义了 equals 和 hashcode 方法
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this); // 构建代理类,invocation handler 就是当前实例
}
本例事务代理类实现的接口

对代理类的创建过程进行一下总结,我们首先是从环境中获取到了本例中唯一的一个 advisor,将其注入到了 ProxyFactory 中,然后就是通过 ProxyFactory 来构建 JdkDynamicAopProxy 实例,它可以看做是一个工厂类,最后就是通过它来构建我们的代理类,代理类实现了上图中的四个接口,我们本例关心的 UserService 接口就在其中,传入的 InvocationHandler 就是 JdkDynamicAopProxy 实例,下一部分的内容就是看该实例的 invoke 方法实现。

事务执行过程

上文已经指出了代理类在执行目标方法时,会直接调用 InvocationHandler 的 invoke 方法,那么这一部分,我们将分析 invoke 方法的实现是怎样的。我已经将 invoke 方法的实现代码贴出来了,内容比较长,但我们真正需要关心的就是后半部分,前边的代码只是针对特殊方法调用的处理,我暂时没有去深入了解,同样的不影响我们对于 spring 事务机制实现原理的理解。跟 cglib 代理方式一样,本段代码中 if (this.advised.exposeProxy) 这个代码块也对代理类的暴露进行了处理,这样我们就能在我们的用户代码中拿到当前代理类,详细的使用方式参考上一篇文章的示例代码二。

org.springframework.aop.framework.JdkDynamicAopProxy#invoke

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;

TargetSource targetSource = this.advised.targetSource; // 这里是目标类
Object target = null;

try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) { // 对于 equals 方法的处理
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) { // 对于 hashcode 方法的处理
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) { // 对于 DecoratingProxy 接口方法的处理
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() && // 对于 Advised 接口实现类方法的处理
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}

Object retVal;

if (this.advised.exposeProxy) { // 看是否需要暴露代理类
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}

// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget(); // 获取目标实例
Class<?> targetClass = (target != null ? target.getClass() : null); // 获取目标实例类
// 尝试从缓存中获取 interceptorList,没有的话就从当前实例中获取(获取 Advised 的全部 advisors,看 advisor 是否适配当前方法,适配的话从 advisor 中获取到 Advice,然后将其添加到 interceptorList 集合返回)
// Get the interception chain for this method.
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
MethodInvocation invocation = // 构建 ReflectiveMethodInvocation 来控制 interceptor 链的调用
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
}

// Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}

下边代码的后半部分就是我们应该关注的点了,首先是拦截器链的获取,通过 this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass); 这段代码进行,上文我们已经指出了 InvocationHandler 持有了 ProxyFactory,而这句代码的 advised 实例其实就是 ProxyFactory,它持有了我们开篇中指出的五个 bean 中的 BeanFactoryTransactionAttributeSourceAdvisor(增强器)对吗?好了那么这里的拦截器链就是通过它来获取的,过程比较繁琐,我也不想细究它每一行代码是怎样的,只需要了解上文中指出的,在进行标签的解析时,BeanFactoryTransactionAttributeSourceAdvisor 对应的 BeanDefinition 是持有了 TransactionInterceptor 实例的唯一标识符的,就凭这一点,再通过 BeanFactoryTransactionAttributeSourceAdvisor 拿到 TransactionInterceptor 就不是什么难以理解的事了,所以这里只给出最终的获取结果就好。特别注意哦这个唯一的拦截器是不是也很熟悉啊??没错,正好就是本文开篇指出的那个五个 bean 中的 TransactionInterceptor(事务实现的核心拦截器,事务的回滚都是在其中完成)对吗?这是一个很关键的拦截器,事务的实现就是靠它。

拦截器链内容

再回到我们的分析点,就是 JdkDynamicAopProxy#invoke 方法中获取拦截器链的那句,我们已经拿到了必要的拦截器链,里边就只有一个拦截器 TransactionInterceptor。接着就是一个 if-else 分支,我们这里的拦截器链是有内容的,所以走 else 分支如下,里边的逻辑又跟 cglib 的拦截器链调用过程一样了,新构建出来的 ReflectiveMethodInvocation 类持有了代理相关的大部分信息,它还负责着拦截器链的调用流程。

1
2
3
4
5
// We need to create a method invocation...
MethodInvocation invocation = // 构建 ReflectiveMethodInvocation 来控制 interceptor 链的调用
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();

想都不用想,invocation.proceed(); 方法将会触发拦截器链第一个节点的逻辑,也就是 TransactionInterceptor 方法,尽管已经猜到了,我还是要贴出 invocation.proceed(); 代码实现如下,因为是第一次调用,所以这里的 currentInterceptorIndex 值为 -1,interceptorsAndDynamicMethodMatchers 其实就是我们的拦截器链,它是在构造函数中被初始化的,里边就只有一个元素为 TransactionInterceptor 实例,根据以上条件,程序将会执行最后一行代码 return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);,即 TransactionInterceptor 实例的 invoke 方法了,我们跟进去看实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Override
@Nullable
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint(); // 这里就是触发连接点方法
}

Object interceptorOrInterceptionAdvice = // 逐个获取 interceptorOrInterceptionAdvice
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
// Evaluate dynamic method matcher here: static part will already have
// been evaluated and found to match.
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
// Dynamic matching failed.
// Skip this interceptor and invoke the next in the chain.
return proceed();
}
}
else {
// It's an interceptor, so we just invoke it: The pointcut will have
// been evaluated statically before this object was constructed. // 对逐个获取的 interceptorOrInterceptionAdvice 进行 invoke 调用
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this); // 参数为通过代理各项参数构建的 CglibMethodInvocation
}
}

实现如下,常规操作,只有这里采用了一个特殊的传参方式,传入的是一个方法引用,了解就好,继续往下跟。

1
2
3
4
5
6
7
8
9
public Object invoke(MethodInvocation invocation) throws Throwable {
// Work out the target class: may be {@code null}.
// The TransactionAttributeSource should be passed the target class
// as well as the method, which may be from an interface. 获取目标类的类型
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

// Adapt to TransactionAspectSupport's invokeWithinTransaction...
return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}

终于到了我们期待已久的事务实现逻辑代码了,赶紧的贴出源码开心一下,代码主干分为两个分支,就本例而言,我们只使用到了 if 分支,所以就只截取这一部分展示。而没用到的那一部分,我就没有做深入了解了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
@Nullable	// 触发真正的业务逻辑,如果发生异常就进行回滚,否则进行事务的提交
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {

if (this.reactiveAdapterRegistry != null) { // 暂不做了解
ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(method.getReturnType());
if (adapter != null) {
return new ReactiveTransactionSupport(adapter).invokeWithinTransaction(method, targetClass, invocation);
}
}

// If the transaction attribute is null, the method is non-transactional.
TransactionAttributeSource tas = getTransactionAttributeSource();
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
final PlatformTransactionManager tm = determineTransactionManager(txAttr); // 获取事务管理器,尝试从缓存中获取 PlatformTransactionManager,没有的话就从 BeanFactory 中获取,缓存后进行返回
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr); // 获取方法的全限定名,没有的话通过 TransactionAttribute 的描述符代替

if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls. // 将 TransactionAttribute 封装为 DelegatingTransactionAttribute,从 PlatformTransactionManager 中获取 TransactionStatus
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification); // 最后构建 TransactionInfo(通过参数构建 TransactionInfo,设置了状态信息, 将事务信心保存到线程本地变量中,同时保留了原先的事务信息,返回)

Object retVal;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
retVal = invocation.proceedWithInvocation(); // 继续下一个 advice 的调用,如果没有后续的 advice,直接进行目标方法的的调用
}
catch (Throwable ex) {
// target invocation exception
completeTransactionAfterThrowing(txInfo, ex); // 对于异常发生后,事物的处理方式,提交或者回滚
throw ex;
}
finally { // 恢复线程本地变量中的 TransactionInfo
cleanupTransactionInfo(txInfo);
}

if (vavrPresent && VavrDelegate.isVavrTry(retVal)) {
// Set rollback-only in case of Vavr failure matching our rollback rules...
TransactionStatus status = txInfo.getTransactionStatus();
if (status != null && txAttr != null) {
retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
}
}
// 正常情况下,进行事务的提交
commitTransactionAfterReturning(txInfo);
return retVal;
}
}

先看 TransactionAttributeSource tas = getTransactionAttributeSource(); 这句,它做的事情就是获取它持有的 TransactionAttributeSource 实例,不知道它具体是什么吗??直接给出结果就知道了,又是一个熟悉的类,没错就是本文开篇中那五个 bean 中的 AnnotationTransactionAttributeSource(主要是用来存储一些事务相关的属性信息)。它有一个属性 attributeCache,是一个 ConcurrentHashMap 实例,本例中里边有 528 项记录。不要慌,其实这些记录中只有两项的值不为空。其他的都是空值,我们所要关注的也就只有这不为空的两项,他们的 key 就是本例中位于 UserService 接口和 UserServiceImpl 实现类中两个 save 方法对应的 MethodClassKey 实例,而对应的值呢,就是对这两个方法进行调用时事务相关的一些属性值,也就是说在这 528 项中,只有值不为空的两项他们对应的方法被调用时会触发事务机制,否则是不会触发事务机制的。如果觉得比较绕,那就还是请继续看后边的分析吧。

TransactionAttributeSource 实例内容

接着就是从 TransactionAttributeSource 中获取事务相关的属性 TransactionAttribute,我们这里调用的是 UserServiceImpl 类的 save 方法,上边已经指出了在 attributeCache 缓存中,该方法对应的值不为空,这样我们获取的 TransactionAttribute 就不是空,再调用 determineTransactionManager(txAttr); 这个方法获取事务管理器,其实就本例而言,获取的过程跟参数没啥关系,因为参数 txAttr 中的 qualifier 属性为空串,所以获取事务管理器时就是依据 TransactionAspectSupport#transactionManagerBeanName 字段来获取的,具体的代码就不贴了,就本例而言,根本拿到的就是我们在 spring 配置文件中指定的那个 “transactionManager”,它持有了配置文件中指定的 dataSource 如下图,了解这个就完事。

transactionManager 实例内容

再往下就是 final String joinpointIdentification = methodIdentification(method, targetClass, txAttr); 这行代码,从方法名就知道这是一个方法的唯一标识符,怎么来的不用深究,直接给出结果。

方法的唯一标识符

再往下就是构建 TransactionInfo 实例,和事务操作相关的信息都封装在其中,代码如下,也没有什么要注意的地方,注释中已经对代码进行了解释,反正最终返回的就是构建出来的 TransactionInfo,它持有了 TransactionManager、TransactionAttribute、方法的唯一标识符信息,知道这些就行了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 将 TransactionAttribute 封装为 DelegatingTransactionAttribute,从 PlatformTransactionManager 中获取 TransactionStatus
@SuppressWarnings("serial") // 最后构建 TransactionInfo(通过参数构建 TransactionInfo,设置了状态信息, 将事务信心保存到线程本地变量中,同时保留了原先的事务信息,返回)
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {

// If no name specified, apply method identification as transaction name.
if (txAttr != null && txAttr.getName() == null) { // 将 TransactionAttribute 封装为 DelegatingTransactionAttribute
txAttr = new DelegatingTransactionAttribute(txAttr) {
@Override
public String getName() {
return joinpointIdentification;
}
};
}

TransactionStatus status = null;
if (txAttr != null) {
if (tm != null) {
status = tm.getTransaction(txAttr);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
"] because no transaction manager has been configured");
}
}
} // 通过参数构建 TransactionInfo,设置了状态信息, 将事务信心保存到线程本地变量中,同时保留了原先的事务信息,返回
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}

再往下走就是执行 retVal = invocation.proceedWithInvocation(); ,这里的 invocation 就是用来控制拦截器链执行的实例的 proceed 方法,是通过函数引用的方式传进来的,这一点上文已经说过了,我们已经执行过一次它的 proceed 方法了,被调用的是 TransactionInterceptor 拦截器,因为一共就只有只有一个拦截器,所以本次 ReflectiveMethodInvocation#proceed 方法的调用就会满足 if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) 判断条件,根据上一篇文章的分析,我们知道这将会导致用户代码的调用,也就是业务逻辑中进行数据库的插入操作。因为这个业务逻辑中,我们人为的抛出了一个运行时异常,所以这个异常就会被上层代码所捕获,而捕获点就是 TransactionAspectSupport#invokeWithinTransaction 方法的 catch (Throwable ex) 处,事务的回滚操作也就是在这里完成的。

在该 catch 代码块中核心就是调用了 completeTransactionAfterThrowing 方法,从方法名就知道其中的核心实现就是完成异常捕获后的事务处理,完整的方法实现如下,根据 if-else 的分支结构,我们就能知道就算是异常出现,那么对于事务的处理也是有两种模式的,if 代码块中的 rollback 方法名我们就能知道这里进行的是回滚操作,而 else 代码块中的 commit 方法名,我们知道是提交操作,也就是说不进行回滚。那么 if 判断成立的条件是什么呢??第一条很明显,就是事务信息 TransactionInfo 持有的事务属性 transactionAttribute 不能为空,其次就是事务属性 transactionAttribute 的 rollbackOn 方法的返回结果了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 对于异常发生后,事物的处理方式,提交或者回滚
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (logger.isTraceEnabled()) {
logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
"] after exception: " + ex);
} // 第二个条件主要是判断回滚规则,最基本的就是在发生运行时异常和错误时发生回滚
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
try {
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus()); // 事务回滚
}
catch (TransactionSystemException ex2) {
logger.error("Application exception overridden by rollback exception", ex);
ex2.initApplicationException(ex);
throw ex2;
}
catch (RuntimeException | Error ex2) {
logger.error("Application exception overridden by rollback exception", ex);
throw ex2;
}
}
else {
// We don't roll back on this exception.
// Will still roll back if TransactionStatus.isRollbackOnly() is true.
try { // 如果捕获到的异常不满足回滚规则,直接进行提交
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
catch (TransactionSystemException ex2) {
logger.error("Application exception overridden by commit exception", ex);
ex2.initApplicationException(ex);
throw ex2;
}
catch (RuntimeException | Error ex2) {
logger.error("Application exception overridden by commit exception", ex);
throw ex2;
}
}
}
}

我们看 rollbackOn 方法的根本实现如下,上半部分的 rollbackRules 的处理部分我没有看懂它的意思,因为就本例而言,上边的判断条件确实没用上,所以不太好理解它的意思。紧接着下边又有一个判断条件,即 return super.rollbackOn(ex); 这句代码,它是在父类中实现的,我们点进去就能知道,它会对捕获到的异常进行判断,如果是运行时异常或者是 Error 错误,那么就会返回 true,否则返回 false。

org.springframework.transaction.interceptor.RuleBasedTransactionAttribute#rollbackOn

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Override	// 这里主要是判断回滚规则,最基本的就是在发生运行时异常和错误时发生回滚
public boolean rollbackOn(Throwable ex) {
if (logger.isTraceEnabled()) {
logger.trace("Applying rules to determine whether transaction should rollback on " + ex);
}

RollbackRuleAttribute winner = null;
int deepest = Integer.MAX_VALUE;

if (this.rollbackRules != null) {
for (RollbackRuleAttribute rule : this.rollbackRules) {
int depth = rule.getDepth(ex);
if (depth >= 0 && depth < deepest) {
deepest = depth;
winner = rule;
}
}
}

if (logger.isTraceEnabled()) {
logger.trace("Winning rollback rule is: " + winner);
}

// User superclass behavior (rollback on unchecked) if no rule matches.
if (winner == null) {
logger.trace("No relevant rollback rule found: applying default rules");
return super.rollbackOn(ex); // 这里说明只有在发生运行时异常和错误时才会触发回滚
}

return !(winner instanceof NoRollbackRuleAttribute);
}

再回到我们 if 分支那里,因为我们在业务代码中抛出的异常是运行时异常,所以 if 判断的第二个条件也是成立的,也就是说我们将要进行事务的回滚操作。但是如果我们将业务代码中的异常修改为非运行异常,那么此时事务就会正常提交。这样带来的结果就是数据入库了。还是看看事务回滚的代码实现吧,根本的就是调用的下边的代码,更加细节的部分我已经没有去深究了,因为到这里对于理解事务机制的实现已经足够了,我这里就仅仅是将代码段的作用给进行标注。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// 尝试调用事务同步器的前置处理方法,进行事务的回滚操作,逐个触发同步器链每个元素的 afterCompletion 方法,最后事务回滚后的扫尾工作,设置事务的状态, 线程本地变量中移除资源信息(连接信息),设置连接的自动提交,恢复隔离级别,释放连接,恢复 connection holder 的状态信息
private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
try {
boolean unexpectedRollback = unexpected; // 预期外的回滚

try { // 尝试调用事务同步器的前置处理方法
triggerBeforeCompletion(status);

if (status.hasSavepoint()) { // 看事务状态是否有保存点
if (status.isDebug()) {
logger.debug("Rolling back transaction to savepoint");
}
status.rollbackToHeldSavepoint(); // 回滚到保存点
}
else if (status.isNewTransaction()) { // 是否是新事务呢?
if (status.isDebug()) {
logger.debug("Initiating transaction rollback");
} // 直接进行回滚
doRollback(status); // 进行事务的回滚操作
}
else { // 不是新事务的处理方式,存在现有的事务处理方式
// Participating in larger transaction
if (status.hasTransaction()) { // 检查回滚条件
if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) { // 如果局部的事务失败,是否设置全局的事务回滚状态
if (status.isDebug()) {
logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
}
doSetRollbackOnly(status); // 仅仅是设置回滚的标志
}
else {
if (status.isDebug()) {
logger.debug("Participating transaction failed - letting transaction originator decide on rollback");
}
}
}
else {
logger.debug("Should roll back transaction but cannot - no transaction available");
}
// Unexpected rollback only matters here if we're asked to fail early
if (!isFailEarlyOnGlobalRollbackOnly()) {
unexpectedRollback = false;
}
}
}
catch (RuntimeException | Error ex) { // 触发
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
throw ex;
}
// 逐个触发同步器链每个元素的 afterCompletion 方法
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);

// Raise UnexpectedRollbackException if we had a global rollback-only marker
if (unexpectedRollback) {
throw new UnexpectedRollbackException(
"Transaction rolled back because it has been marked as rollback-only");
}
}
finally { // 事务回滚后的扫尾工作,设置事务的状态, 线程本地变量中移除资源信息(连接信息),设置连接的自动提交,恢复隔离级别,释放连接,恢复 connection holder 的状态信息
cleanupAfterCompletion(status);
}
}

只要注意一点,就是真正的事务回滚是在上边代码中的 doRollback(status); 语句中完成的,而其他部分就只是一些事务回滚生命周期方法的处理,或者是对于事务回滚后的一些善后工作。关于 doRollback(status); 的实现,我们不妨看看,其实就是跟我们自己进行事务回滚的操作一样,根本还是调用的 java.sql.Connection#rollback() 看到这里我想小伙伴已经对 spring 的事务实现有比较清晰的理解了,至于一些其他的细节部分,如果有精力就可以去看。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override	// 进行事务的回滚操作
protected void doRollback(DefaultTransactionStatus status) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction(); // 数据源事务对象
Connection con = txObject.getConnectionHolder().getConnection(); // 也就是说和数据库交互相关的信息都保存在 DataSourceTransactionObject 实例中
if (status.isDebug()) {
logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");
}
try {
con.rollback(); // 调用真正的回滚操作
}
catch (SQLException ex) {
throw new TransactionSystemException("Could not roll back JDBC transaction", ex);
}
}

最后对 spring 事务代理类的执行过程进行一下总结,我们会从环境中获取到 Advisors 信息,然后根据它来得到拦截器链,而拦截器链的执行是由 ReflectiveMethodInvocation 实例控制的,就我们本例而言,这里拦截器链只有一个元素,就是 TransactionInterceptor 实例,我们将要调用它的 invoke 方法,该方法中会继续下一个拦截器的执行,当所有拦截器执行完后,就会触发用户代码,如果此时用户代码中抛出了运行时异常,只要该异常到达 TransactionInterceptor 被捕获,那么该拦截器就会根据必要的条件来进行事务的回滚或者提交操作。