死磕Spring之AOP篇

Posted 月圆吖

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了死磕Spring之AOP篇相关的知识,希望对你有一定的参考价值。

该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读。

Spring 版本:5.1.14.RELEASE

在开始阅读 Spring AOP 源码之前,需要对 Spring IoC 有一定的了解,可查看我的 《死磕Spring之IoC篇 - 文章导读》 这一系列文章

了解 AOP 相关术语,可先查看 《Spring AOP 常见面试题) 》 这篇文章

该系列其他文章请查看:《死磕 Spring 之 AOP 篇 - 文章导读》

前序

前面我的一系列文章对 Spring AOP 进行了比较详细的讲述,相信你对 Spring AOP 有了更加深入的理解,如果你对于 Spring AOP 不是很了解,建议先查看我前面的一系列文章对 Spring AOP 有一定的了解,因为 Spring 事务是借助于 Spring AOP 实现的。由于这段时间有点忙(太懒了~),没能及时更新 Spring AOP 在 Spring 内部的应用相关内容,趁着还对 Spring AOP 有一点印象,我们一起来看看 Spring 事务的相关源码。我猜应该是比较容易理解的,因为已经有了 Spring AOP 的基础,相信对于 Spring 事务会“轻而易举”地掌握,嘻嘻~

我们先了解一下 Spring 事务里面的“物理事务”和“逻辑事务”,所谓的“物理事务”是指 JDBC 的事务,上一次事务和本次事务之间是没有其他事务的,在执行一条命令(默认行为自动提交)都会产生一个事务,如果把 autocommit 设置为 false,需要主动 commit 才完成一个事务。所谓的“逻辑事务”是 Spring 对 JDBC 的一个抽象,例如 Spring 默认的事务传播行为是 REQUIRED,当执行 @Transactional 注解标注的方法时,如果此时正处于一个事务(物理事务)中,那么加入到这个事务中,你可以理解为创建了一个“逻辑事务”,进行提交的时候不会执行 Connection 的 commit 方法,而是在外面的“物理事务”中进行 commit 时一并完成本次事务。

Spring 事务的传播级别

  • REQUIRED:默认传播级别,如果正处于一个事务中,则加入;否则,创建一个事务
  • SUPPORTS:如果正处于一个事务中,则加入;否则,不使用事务
  • MANDATORY:如果当前正处于一个事务中,则加入;否则,抛出异常
  • REQUIRES_NEW:无论如何都会创建一个新的事务,如果正处于一个事务中,会先挂起,然后创建
  • NOT_SUPPORTED:不使用事务,如果正处于一个事务中,则挂起,不使用事务
  • NEVER:不使用事务,如果正处于一个事务中,则抛出异常
  • NESTED:嵌套事务,如果正处于一个事务中,则创建一个事务嵌套在其中(mysql 采用 SAVEPOINT 保护点实现的);否则,创建一个事务

关于 Spring 事务传播级别更多的细节在接下来的源码中进行讨论

Spring 事务的使用示例

相信看到这篇文章的你对于 @Transactional 注解的使用肯定非常了解,不过这里还是列举以下它的使用方式

Spring MVC

引入 Spring 事务相关依赖后,在 Spring MVC 中有两种(XML 配置和注解)驱动 Spring 事务的方式,如下面所示:

方式一:

<?xml version="1.0" encoding="UTF-8"?>
<beans>
    <!-- 定义一个数据源 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">...</bean>
    <!-- 事务管理器 -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- 指定数据源 -->
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!-- 事务模块驱动,指定使用上面定义事务管理器,默认值为 transactionManager -->
    <tx:annotation-driven transaction-manager="txManager"/>
</beans>

方式二:

需要在 Spring 能扫描的一个 Bean 上添加一个 @EnableTransactionManagement 注解,然后添加一个 TransactionManagementConfigurer 实现类,如下:

package tk.mybatis.simple.controller;

import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.TransactionManagementConfigurer;

import javax.annotation.Resource;
import javax.sql.DataSource;

@Configuration
@EnableTransactionManagement
public class TransactionManagerConfig implements TransactionManagementConfigurer {

    @Resource
    DataSource dataSource;

    @Override
    public TransactionManager annotationDrivenTransactionManager() {
        // 返回一个事务管理器,设置数据源
        return new DataSourceTransactionManager(dataSource);
    }
}

此时你可以使用 @Transactional 注解标注在方法(或者类)上面,使得方法的执行处于一个事务中,如下:

@Transactional(propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
public void update(){
    try {
        // 数据库操作
    } catch (Exeception e){
        // 将事务状态设置为回滚
        TransactionInterceptor.currentTransactionStatus().setRollbackOnly();
    }
}

Spring Boot

在 Spring Boot 中我们使用 @Transactional 注解的时候好像不需要 @EnableTransactionManagement 注解驱动 Spring 事务模块,这是为什么?和 Spring AOP 的 @EnableAspectJAutoProxy 注解类似,会有一个 TransactionAutoConfiguration 事务自动配置类,我们一起来看看:

@Configuration
@ConditionalOnClass(PlatformTransactionManager.class)
@AutoConfigureAfter({ JtaAutoConfiguration.class, HibernateJpaAutoConfiguration.class,
		DataSourceTransactionManagerAutoConfiguration.class,
		Neo4jDataAutoConfiguration.class })
@EnableConfigurationProperties(TransactionProperties.class)
public class TransactionAutoConfiguration {

	@Bean
	@ConditionalOnMissingBean
	public TransactionManagerCustomizers platformTransactionManagerCustomizers(
			ObjectProvider<List<PlatformTransactionManagerCustomizer<?>>> customizers) {
		return new TransactionManagerCustomizers(customizers.getIfAvailable());
	}

	@Configuration
	@ConditionalOnSingleCandidate(PlatformTransactionManager.class)
	public static class TransactionTemplateConfiguration {

		private final PlatformTransactionManager transactionManager;

		public TransactionTemplateConfiguration(
				PlatformTransactionManager transactionManager) {
			this.transactionManager = transactionManager;
		}

		@Bean
		@ConditionalOnMissingBean
		public TransactionTemplate transactionTemplate() {
			return new TransactionTemplate(this.transactionManager);
		}
	}

	@Configuration
	@ConditionalOnBean(PlatformTransactionManager.class)
	@ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)
	public static class EnableTransactionManagementConfiguration {
		@Configuration
		@EnableTransactionManagement(proxyTargetClass = false)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = false)
		public static class JdkDynamicAutoProxyConfiguration { }

		@Configuration
		@EnableTransactionManagement(proxyTargetClass = true)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true)
		public static class CglibAutoProxyConfiguration { }
	}
}

是不是很熟悉,只要存在 PlatformTransactionManager 这个 Class 对象就会将这个 Bean 注册到 IoC 容器中,里面涉及到一些 @Conditional 注解,这里就不一一解释了。可以看到其中会有 @EnableTransactionManagement 注解,是不是和在 Spring MVC 中以注解驱动 Spring 事务的方式一样,但是好像没有 PlatformTransactionManager 事务管理器。别急,我们看到这个自动配置类上面会有 @AutoConfigureAfter({DataSourceTransactionManagerAutoConfiguration.class}) 注解,表示会先加载 DataSourceTransactionManagerAutoConfiguration 这个自动配置类,我们一起来看看:

@Configuration
@ConditionalOnClass({ JdbcTemplate.class, PlatformTransactionManager.class })
@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceTransactionManagerAutoConfiguration {

	@Configuration
	@ConditionalOnSingleCandidate(DataSource.class)
	static class DataSourceTransactionManagerConfiguration {

		private final DataSource dataSource;

		private final TransactionManagerCustomizers transactionManagerCustomizers;

		DataSourceTransactionManagerConfiguration(DataSource dataSource,
				ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
			this.dataSource = dataSource;
			this.transactionManagerCustomizers = transactionManagerCustomizers
					.getIfAvailable();
		}

		@Bean
		@ConditionalOnMissingBean(PlatformTransactionManager.class)
		public DataSourceTransactionManager transactionManager(
				DataSourceProperties properties) {
			DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(
					this.dataSource);
			if (this.transactionManagerCustomizers != null) {
				this.transactionManagerCustomizers.customize(transactionManager);
			}
			return transactionManager;
		}
	}
}

可以看到会注入一个 DataSourceTransactionManager 事务管理器,关联这个当前 DataSource 数据源对象

好了,通过上面的使用示例我们可以注意到 @EnableTransactionManagement 注解可以驱动整个 Spring 事务模块,当然,<annotation-driven /> 标签的原理和注解差不多,前面也讲述了非常多 Spring 自定义标签的实现原理,这里我们就不分析了,那么我们一起来看看 @EnableTransactionManagement 这个注解

核心 API

在开始查看 Spring 事务的源码之前,我想有必要先简单介绍一下涉及到的一些主要的 API,对 Spring 事务的源码有一个印象,如下:

  • Spring 事务 @Enable 模块驱动 - @EnableTransactionManagement
  • Spring 事务注解 - @Transactional
  • Spring 事务事件监听器 - @TransactionalEventListener
  • Spring 事务定义 - TransactionDefinition
  • Spring 事务状态 - TransactionStatus
  • Spring 平台事务管理器 - PlatformTransactionManager
  • Spring 事务代理配置 - ProxyTransactionManagementConfiguration
  • Spring 事务 PointAdvisor 实现 - BeanFactoryTransactionAttributeSourceAdvisor
  • Spring 事务 MethodInterceptor 实现 - TransactionInterceptor
  • Spring 事务属性源 - TransactionAttributeSource

简单介绍 Spring 事务:

  1. 需要通过 @EnableTransactionManagement 注解驱动整个 Spring 事务模块

  2. 可以通过 @Transactional 注解定义在某个类或者方法上面定义一个事务(传播性、隔离性等),开启事务

  3. ProxyTransactionManagementConfiguration 代理配置类用来定义一个 BeanFactoryTransactionAttributeSourceAdvisor 切面,是一个用于 Spring 事务的 AOP 切面

  4. Spring 事务底层就是通过 Spring AOP 实现的,可以在上面看到有一个 PointcutAdvisor 切面,关联的 Pointcut 内部有一个 TransactionAttributeSource 对象,会借助于 TransactionAnnotationParser 解析器解析 @Transactional 注解,将这个事务定义的一些属性封装成一个 TransactionDefinition 事务定义对象

  5. Spring AOP 拦截处理在 TransactionInterceptor 事务拦截器中,先借助 PlatformTransactionManager 平台事务管理器创建 TransactionStatus 事务对象,里面包含了 Transaction 事务,将 autocommit 自动提交关闭,方法的执行也就处于一个事务中

  6. 事务的相关属性会保存在许多 ThreadLocal 中,例如 DataSource、Connection 和 SqlSession 等属性,交由一个 TransactionSynchronizationManager 事务同步管理器进行管理,所以说 Spring 事务仅支持在一个线程中完成

Spring 事务非常复杂,接下来我们逐步分析

@EnableTransactionManagement 注解驱动

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {

	/**
	 * 默认优先使用 JDK 动态代理
	 */
	boolean proxyTargetClass() default false;

    /**
     * 默认使用 Spring AOP 代理模式
     */
	AdviceMode mode() default AdviceMode.PROXY;

	int order() default Ordered.LOWEST_PRECEDENCE;
}

可以看到有一个 @Import 注解,它的值是一个 TransactionManagementConfigurationSelector 类,也就是说 Spring 事务的驱动入口在这里面,关于 @Import 注解的原理可查看我的 《死磕Spring之IoC篇 - @Bean 等注解的实现原理》 这篇文章

TransactionManagementConfigurationSelector

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {

	@Override
	protected String[] selectImports(AdviceMode adviceMode) {
		switch (adviceMode) {
			// 默认使用代理模式
			case PROXY:
				return new String[]{
						// 注册一个 InfrastructureAdvisorAutoProxyCreator 对象,目的是创建代理对象
						AutoProxyRegistrar.class.getName(),
						// 【关键】注册一个 Spring 事务代理配置类
						ProxyTransactionManagementConfiguration.class.getName()};
			// 选择 AspectJ 模式
			case ASPECTJ:
				return new String[]{determineTransactionAspectClass()};
			default:
				return null;
		}
	}

	private String determineTransactionAspectClass() {
		return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
				TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
				TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
	}
}

可以看到默认情况下会注册两个 Bean

  • AutoProxyRegistrar,注册一个 InfrastructureAdvisorAutoProxyCreator 对象,目的是创建代理对象,在讲解 Spring AOP 的时候讲述过,这里不再赘述
  • ProxyTransactionManagementConfiguration,一个 Spring 务代理配置类

ProxyTransactionManagementConfiguration

org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration,Spring 事务代理配置类,定义好一个 AOP 切面

@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
		// <1> 创建 PointcutAdvisor 对象,作为 @Transactional 注解的一个切面
 		BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
		// <2> 【Pointcut】设置 AnnotationTransactionAttributeSource,被关联在 Pointcut 中
		// 借助于 TransactionAnnotationParser 解析器解析 @Transactional 注解
		advisor.setTransactionAttributeSource(transactionAttributeSource());
		// <3> 【Advice】设置 Advice 为 TransactionInterceptor 事务拦截器
		advisor.setAdvice(transactionInterceptor());
		if (this.enableTx != null) {
			advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
		}
		return advisor;
	}

	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionAttributeSource transactionAttributeSource() {
		return new AnnotationTransactionAttributeSource();
	}

	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionInterceptor transactionInterceptor() {
		// 创建 TransactionInterceptor 事务拦截器(MethodInterceptor 对象)
		TransactionInterceptor interceptor = new TransactionInterceptor();
		// 设置这个 AnnotationTransactionAttributeSource 对象,@Bean 注解标注的方法返回的都是同一个对象
		interceptor.setTransactionAttributeSource(transactionAttributeSource());
		if (this.txManager != null) {
			// 设置默认的事务管理器
			interceptor.setTransactionManager(this.txManager);
		}
		return interceptor;
	}
}

可以看到会注册三个 Bean:

  1. BeanFactoryTransactionAttributeSourceAdvisor 切面,这个 PointcutAdvisor 对象关联的 Pointcut 切点用于筛选 @Transactional 注解的方法(标注在类上也可以),在关联的 Advice 中会进行事务的拦截处理

  2. Advice 通知,就是一个 TransactionInterceptor 方法拦截器,关联着一个 AnnotationTransactionAttributeSource 对象

  3. AnnotationTransactionAttributeSource 事务属性资源对象,被 Pointcut 和 Advice 关联,用于解析 @Transactional 注解,在它的构造方法中会添加一个 SpringTransactionAnnotationParser 事务注解解析器,用于解析 @Transactional 注解,如下:

    // AnnotationTransactionAttributeSource.java
    public AnnotationTransactionAttributeSource() {
        this(true);
    }
    
    public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
        this.publicMethodsOnly = publicMethodsOnly;
        if (jta12Present || ejb3Present) {
            this.annotationParsers = new LinkedHashSet<>(4);
            this.annotationParsers.add(new SpringTransactionAnnotationParser());
            if (jta12Present) {
                this.annotationParsers.add(new JtaTransactionAnnotationParser());
            }
            if (ejb3Present) {
                this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
            }
        }
        else {
            this.annotationParsers = Collections.singleton(new SpringTransactionAnnotationParser());
        }
    }
    

PointcutAdvisor 事务切面

org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor,Spring 事务切面,如下:

public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {

	/**
	 * 事务属性源对象,用于解析 @Transactional 注解
	 */
	@Nullable
	private TransactionAttributeSource transactionAttributeSource;

	/**
	 * Pointcut 对象,用于判断 JoinPoint 是否匹配
	 */
	private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
		@Override
		@Nullable
		protected TransactionAttributeSource getTransactionAttributeSource() {
			return transactionAttributeSource;
		}
	};
    
	public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
		this.transactionAttributeSource = transactionAttributeSource;
	}

	public void setClassFilter(ClassFilter classFilter) {
		this.pointcut.setClassFilter(classFilter);
	}

	@Override
	public Pointcut getPointcut() {
		return this.pointcut;
	}
}

设置的 TransactionAttributeSource 就是上面的 AnnotationTransactionAttributeSource 对象,关联的 Pointcut 切点就是一个 TransactionAttributeSourcePointcut 对象

也就是说通过 Pointcut 事务切点筛选出来的 Bean 会创建一个代理对象,方法的拦截处理则交由 Advice 完成

Pointcut 事务切点

org.springframework.transaction.interceptor.TransactionAttributeSourcePointcut,Spring 事务的 AOP 切点,如下:

abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {

	@Override
	public boolean matches(Method method, Class<?> targetClass) {
		// <1> 目标类是 Spring 内部的事务相关类,则跳过,不需要创建代理对象
		if (TransactionalProxy.class.isAssignableFrom(targetClass) ||
				PlatformTransactionManager.class.isAssignableFrom(targetClass) ||
				PersistenceExceptionTranslator.class.isAssignableFrom(targetClass)) {
			return false;
		}
		// <2 获取 AnnotationTransactionAttributeSource 对象
		TransactionAttributeSource tas = getTransactionAttributeSource();
		// <3> 解析该方法相应的 @Transactional 注解,并将元信息封装成一个 TransactionAttribute 对象
		// 且缓存至 AnnotationTransactionAttributeSource 对象中
		// <4> 如果有对应的 TransactionAttribute 对象,则表示匹配,需要进行事务的拦截处理
		return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
	}
}

判断这个方法是否需要被 TransactionInterceptor 事务拦截器进行拦截的过程如下:

  1. 目标类是 Spring 内部的事务相关类,则跳过,不需要创建代理对象
  2. 获取 AnnotationTransactionAttributeSource 对象
  3. 解析该方法相应的 @Transactional 注解,并将元信息封装成一个 TransactionAttribute 对象,且缓存至 AnnotationTransactionAttributeSource 对象中
  4. 如果有对应的 TransactionAttribute 对象,则表示匹配,需要进行事务的拦截处理

3 步解析 @Transactional 注解通过 AnnotationTransactionAttributeSource#getTransactionAttribute(..) 方法完成的,我们一起来看看这个解析过程

@Transactional 注解的解析

1. getTransactionAttribute 方法
// AbstractFallbackTransactionAttributeSource.java
@Override
@Nullable
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
    // <1> java.lang.Object 内定义的方法跳过
    if (method.getDeclaringClass() == Object.class) {
        return null;
    }
    // First, see if we have a cached value.
    // <2> 获取缓存 Key,MethodClassKey 对象,关联 Method 和 Class 对象
    Object cacheKey = getCacheKey(method, targetClass);
    // <3> 尝试从缓存中获取该方法对应的 TransactionAttribute 对象
    TransactionAttribute cached = this.attributeCache.get(cacheKey);
    if (cached != null) {
        // Value will either be canonical value indicating there is no transaction attribute,
        // or an actual transaction attribute.
        // <3.1> 缓存中缓存的是一个空的 TransactionAttribute 对象
        // 表示没有相应的 @Transactional 注解,返回 `null`
        if (cached == NULL_TRANSACTION_ATTRIBUTE) {
            return null;
        }
        // <3.2> 返回缓存的 TransactionAttribute 对象
        else {
            return cached;
        }
    }
    // <4> 开始解析方法对应的 @Transactional 注解
    else {
        // We need to work it out.
        // <4.1> 解析该方法或者类上面的 @Transactional 注解,封装成 RuleBasedTransactionAttribute 对象
        // 优先从方法上面解析该注解,其次从类上解析该注解,没有的话返回的是 `null`
        TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
        // Put it in the cache.
        // <4.2> 如果是 `null`,则缓存一个空的 TransactionAttribute 对象
        if (txAttr == null) {
            this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
        }
        // <4.3> 否则,将该 TransactionAttribute 对象缓存
        else {
            String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
            if (txAttr instanceof DefaultTransactionAttribute) {
                // 设置方法的描述符(类名.方法名)
                ((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
            }
            this.attributeCache.put(cacheKey, txAttr);
        }
        // <4.4> 返回这个 TransactionAttribute 对象
        return txAttr;
    }
}

解析过程如下:

  1. Object 内定义的方法跳过
  2. 获取缓存 Key,MethodClassKey 对象,关联 Method 和 Class 对象
  3. 尝试从缓存中获取该方法对应的 TransactionAttribute 对象,如果有的话
    1. 如果缓存中缓存的是一个“空”的 TransactionAttribute 对象,表示没有相应的 @Transactional 注解,返回 null
    2. 否则,返回缓存的 TransactionAttribute 对象
  4. 否则,开始解析方法对应的 @Transactional 注解
    1. 解析该方法或者类上面的 @Transactional 注解,封装成 RuleBasedTransactionAttribute 对象,优先从方法上面解析该注解,其次从类上解析该注解,没有的话返回的是 null
    2. 如果是 null,则缓存一个“空”的 TransactionAttribute 对象
    3. 否则,将该 TransactionAttribute 对象缓存
    4. 返回这个 TransactionAttribute 对象

注意,这里解析出来的 TransactionAttribute 会进行缓存,后续在 TransactionInterceptor(Advice)中无需解析,直接取缓存即可

上面第 4.1 步调用 computeTransactionAttribute(..) 方法解析 @Transactional 注解,如下:

2. computeTransactionAttribute 方法
// AbstractFallbackTransactionAttributeSource.java
@Nullable
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
    // Don\'t allow no-public methods as required.
    // 如果不允许非 public 修饰的方法(默认允许),则判断是否为 public 修饰,不是的话返回 null
    if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
        return null;
    }

    // The method may be on an interface, but we need attributes from the target class.
    // If the target class is null, the method will be unchanged.
    // 获取方法对象(而不是桥接方法)
    Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);

    // First try is the method in the target class.
    // 通过 SpringTransactionAnnotationParser 解析方法上面的 @Transactional 注解
    // 并将注解的元信息封装到 RuleBasedTransactionAttribute 中,没有注解的话返回 null
    TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
    if (txAttr != null) {
        // 存在的话直接返回
        return txAttr;
    }

    // Second try is the transaction attribute on the target class.
    // 如果方法上面没有,则尝试解析类上面的 @Transactional 注解
    txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
    // 存在这个注解,且方法是用户级别(不是 Spring 内部合成的)
    if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
        return txAttr;
    }

    // 如果还没有找到 @Transactional 注解的元信息,则尝试从原 Method 对象中查找
    if (specificMethod != method) {
        // Fallback is to look at the original method.
        // 处理过程如上
        txAttr = findTransactionAttribute(method);
        if (txAttr != null) {
            return txAttr;
        }
        // Last fallback is the class of the original method.
        // 处理过程如上
        txAttr = findTransactionAttribute(method.getDeclaringClass());
        if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
            return txAttr;
        }
    }

    return null;
}

可以看到,默认情况是只支持 public 修饰的方法,对于方法和类上面的 @Transactional 注解都是支持的,优先从方法上面解析,其次从所在类上面解析,处理过程都在 findTransactionAttribute(..) 方法中

3. findTransactionAttribute 方法
// AnnotationTransactionAttributeSource.java
@Override
protected TransactionAttribute findTransactionAttribute(Class<?> clazz) {
    // 解析类上面的 @Transactional 注解,并将注解的元信息封装到 RuleBasedTransactionAttribute 中
    return determineTransactionAttribute(clazz);
}

@Override
protected TransactionAttribute findTransactionAttribute(Method method) {
    // 解析方法上面的 @Transactional 注解,并将注解的元信息封装到 RuleBasedTransactionAttribute 中
    return determineTransactionAttribute(method);
}

protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
    for (TransactionAnnotationParser annotationParser : this.annotationParsers) {
        // 通过 SpringTransactionAnnotationParser 解析 @Transactional 注解
        TransactionAttribute attr = annotationParser.parseTransactionAnnotation(element);
        if (attr != null) {
            return attr;
        }
    }
    return null;
}

通过 SpringTransactionAnnotationParser 解析器进行方法或者类上面的 @Transactional 注解

4. SpringTransactionAnnotationParser
public class SpringTransactionAnnotationParser implements TransactionAnnotationParser, Serializable {

	@Override
	@Nullable
	public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
		// 找到这个方法的 @Transactional 注解
		AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
				element, Transactional.class, false, false);
		if (attributes != null) {
			// 将 @Transactional 注解的元信息封装到 RuleBasedTransactionAttribute 对象中
			return parseTransactionAnnotation(attributes);
		}
		else {
			return null;
		}
	}

	public TransactionAttribute parseTransactionAnnotation(Transactional ann) {
		return parseTransactionAnnotation(AnnotationUtils.getAnnotationAttributes(ann, false, false));
	}

	protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
		RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
		// 事务传播性
		Propagation propagation = attributes.getEnum("propagation");
		rbta.setPropagationBehavior(propagation.value());
		// 事务隔离级别
		Isolation isolation = attributes.getEnum("isolation");
		rbta.setIsolationLevel(isolation.value());
		// 超时时间
		rbta.setTimeout(attributes.getNumber("timeout").intValue());
		// 是否只读
		rbta.setReadOnly(attributes.getBoolean("readOnly"));
		// 指定事务管理器
		rbta.setQualifier(attributes.getString("value"));

		List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
		// 设置接收到哪些 Class 对象(异常)需要回滚
		for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
			rollbackRules.add(new RollbackRuleAttribute(rbRule));
		}
		for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
			rollbackRules.add(new RollbackRuleAttribute(rbRule));
		}
		// 设置接收到哪些 Class 对象(异常)不需要回滚
		for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) {
			rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
		}
		for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {
			rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
		}
		rbta.setRollbackRules(rollbackRules);

		return rbta;
	}
}

解析过程比较简单,就是将 @Transactional 注解解析成 RuleBasedTransactionAttribute 对象(实现了 TransactionDefinition 接口),设置相关属性,不存在这个注解的话返回 null

小节

在这个 PointcutAdvisor 切面关联着一个 Pointcut 切点,为 TransactionAttributeSourcePointcut 对象,内部有一个 AnnotationTransactionAttributeSource 事务属性资源对象。在这个切点判断某个方法是否需要进行事务处理时,通过内部的 AnnotationTransactionAttributeSource 对象解析 @Transactional 注解(没有的话表示不匹配),解析过程需要借助于 SpringTransactionAnnotationParser 解析器解析 @Transactional 注解,将这个事务定义的一些属性封装成一个 RuleBasedTransactionAttribute 事务定义对象(实现了 TransactionDefinition 接口),并缓存

TransactionInterceptor 事务拦截处理

通过 Pointcut 事务切点筛选出来的 Bean,会创建一个代理对象,Bean 内部肯定定义了 @Transactional 注解,如果是类上定义的 @Transactional 注解,每个方法都需要进行事务处理。代理对象的事务拦截处理在 TransactionInterceptor 拦截器中,实现了 MethodInterceptor 方法拦截器,也就是实现了 Object invoke(MethodInvocation invocation) 这个方法,一起来看看 TransactionInterceptor 这个类

结构类图:

// TransactionInterceptor.java
@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
    // 目标类
    Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

    // 在事务中执行方法调用器
    return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}

调用 invokeWithinTransaction(..) 方法,在事务中执行方法调用器,如下:

// TransactionAspectSupport.java
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
        final InvocationCallback invocation) throws Throwable {

    // If the transaction attribute is null, the method is non-transactional.
    TransactionAttributeSource tas = getTransactionAttributeSource();
    // <1> 获取 `@Transactional` 注解对应的 TransactionAttribute 对象(如果在 AnnotationTransactionAttributeSource 解析过则取缓存)
    final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
    // <2> 获取 PlatformTransactionManager 事务管理器(可以指定,没有指定则获取默认的)
    final PlatformTransactionManager tm = determineTransactionManager(txAttr);
    // <3> 获取方法的唯一标识,默认都是 `类名.方法名`
    final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

    // <4> 如果已有 `@Transactional` 注解对应的 TransactionAttribute 对象,或者是一个非回调偏向的事务管理器(默认不是)
    if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
        // Standard transaction demarcation with getTransaction and commit/rollback calls.
        // <4.1> 创建 TransactionInfo 事务信息对象,绑定在 ThreadLocal 中
        // 包含一个 DefaultTransactionStatus 事务状态对象
        TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);

        Object retVal;
        try {
            // <4.2> 继续执行方法调用器
            retVal = invocation.proceedWithInvocation();
        }
        catch (Throwable ex) {
            // <4.3> 如果捕获到异常,则在这里完成事务,进行回滚或者提交
            completeTransactionAfterThrowing(txInfo, ex);
            throw ex;
        }
        finally {
            // <4.4> `finally` 语句块,释放 ThreadLocal 中的 TransactionInfo 对象,设置为上一个事务信息对象(没有的话为空)
            cleanupTransactionInfo(txInfo);
        }
        // <4.5> 正常情况,到这里完成事务
        commitTransactionAfterReturning(txInfo);
        // <4.6> 返回执行结果
        return retVal;
    }
    // <5> 否则,就是支持回调的事务管理器,编程式事务(回调偏向),暂时忽略
    else {
        // .....
    }
}

整个过程有点复杂,我们一步一步来看

  1. 获取 @Transactional 注解对应的 TransactionAttribute 对象(如果在 AnnotationTransactionAttributeSource 解析过则取缓存),在 Pointcut 事务切点中已经分析过
  2. 获取 PlatformTransactionManager 事务管理器,需要指定,在 Spring Boot 中默认为 DataSourceTransactionManager
  3. 获取方法的唯一标识,默认都是 类名.方法名
  4. 如果已有 @Transactional 注解对应的 TransactionAttribute 对象,或者不是一个回调偏向的事务管理器(默认不是)
    1. 调用 createTransactionIfNecessary(..) 方法,创建 TransactionInfo 事务信息对象(包含一个 DefaultTransactionStatus 事务状态对象),绑定在 ThreadLocal 中
    2. 继续执行方法调用器(执行方法)
    3. 如果捕获到异常,则在这里完成事务,进行回滚或者提交,调用 completeTransactionAfterThrowing(..) 方法
    4. finally 语句块,释放 ThreadLocal 中的 TransactionInfo 对象,设置为上一个事务信息对象(没有的话为空)
    5. 正常情况,到这里完成事务,调用 commitTransactionAfterReturning(..) 方法
    6. 返回执行结果
  5. 否则,就是支持回调的事务管理器,编程式事务(回调偏向),暂时忽略

整个过程的主流程不复杂,我们可以看到上面的第 4 步,可以把这一步分为四个步骤:

  1. 为本地方法的执行创建一个事务,过程比较复杂,可以先理解为需要把 Connection 连接的 autocommit 关闭,然后根据 @Transactional 注解的属性进行相关设置,例如根据事务的传播级别判断是否需要创建一个新的事务
  2. 事务准备好了,那么继续执行方法调用器,也就是方法的执行
  3. 捕获到异常,进行回滚,或者提交(异常类型不匹配)
  4. 正常情况,走到这里就完成事务,调用 Connection 的 commit() 方法完成本次事务(不是一定会执行,因为可能是“嵌套事务”或者“逻辑事务”等情况)

接下来,我们一起来看看 Spring 是如何创建一个事务的

1. 创建事务

createTransactionIfNecessary(..) 方法,创建一个事务(如果有必要的话),如下:

// TransactionAspectSupport.java
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
        @Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
    // <1> 没有设置事务名称,则封装成一个 DelegatingTransactionAttribute 委托对象,支持返回一个事务名称(类名.方法名)
    if (txAttr != null && txAttr.getName() == null) {
        txAttr = new DelegatingTransactionAttribute(txAttr) {
            @Override
            public String getName() {
                return joinpointIdentification;
            }
        };
    }
    // <2> 获取一个 TransactionStatus 对象
    TransactionStatus status = null;
    if (txAttr != null) {
        // <2.1> 如果存在事务管理器
        if (tm != null) {
            // 从事务管理器中获取一个 TransactionStatus 事务状态对象(对事务的封装),该对象包含以下信息:
            // TransactionDefinition 事务定义、DataSourceTransactionObject 数据源事务对象(包括 DataSource 和 Connection)、
            // 是否是一个新的事务、是否是一个新的事务同步器、被挂起的事务资源对象
            status = tm.getTransaction(txAttr);
        }
        // <2.2> 否则,跳过
        else { }
    }
    // <3> 创建一个 TransactionInfo 事务信息对象,并绑定到 ThreadLocal 中
    return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}

过程如下:

  1. 如果没有设置事务名称,则封装成一个 DelegatingTransactionAttribute 委托对象,支持返回一个事务名称(类名.方法名

  2. 获取一个 TransactionStatus 对象(对事务的封装)

    1. 如果存在事务管理器,Spring Boot 中默认为 DataSourceTransactionManager,则通过事务管理器根据 @Transactional 注解获取一个 TransactionStatus 事务状态对象,该对象是对事务的封装,包含了以下信息:
      • TransactionDefinition 事务定义
      • DataSourceTransactionObject 数据源事务对象(包括 DataSource 和 Connection)
      • 是否是一个新的事务
      • 是否是一个新的事务同步器
      • 被挂起的事务资源对象(如果有)
    2. 否则,跳过
  3. 创建一个 TransactionInfo 事务信息对象,并绑定到 ThreadLocal 中,如下:

    // TransactionAspectSupport.java
    protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm,
            @Nullable TransactionAttribute txAttr, String joinpointIdentification,
            @Nullable TransactionStatus status) {
    
        // <1> 创建一个 TransactionInfo 对象
        TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
        // <2> 如果有 @Transactional 注解的元信息
        if (txAttr != null) {
            // 设置 DefaultTransactionStatus 事务状态对象
            txInfo.newTransactionStatus(status);
        }
        else { }
    
        // We always bind the TransactionInfo to the thread, even if we didn\'t create
        // a new transaction here. This guarantees that the TransactionInfo stack
        // will be managed correctly even if no transaction was created by this aspect.
        // <3> 将当前 TransactionInfo 对象保存至 ThreadLocal 中
        txInfo.bindToThread();
        // <4> 返回这个 TransactionInfo 对象
        return txInfo;
    }
    

    可以看到,即使没有创建事务,也会创建一个 TransactionInfo 对象,并绑定到 ThreadLocal 中

我们继续看到在上面第 2PlatformTransactionManager 事务管理器是如何创建一个 Spring 事务的

1.1 getTransaction 方法

PlatformTransactionManager 事务管理器接口的类图:

该接口就定义了三个方法,如下:

public interface PlatformTransactionManager {

	TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
			throws TransactionException;
			
	void commit(TransactionStatus status) throws TransactionException;


	void rollback(TransactionStatus status) throws TransactionException;
}

三个方法分别对应创建事务,提交,回滚三个操作,关于 Spring 事务也就这三个核心步骤了,我们先来看看 getTransaction(..) 这个方法的实现,如下:

// AbstractPlatformTransactionManager.java
@Override
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
    // <1> 先从当前事务管理器中获取 DataSource 对象,然后尝试以它作为一个 Key 从一个 ThreadLocal 的 Map 中获取对应的 ConnectionHolder 连接对象
    // 会包装成一个 DataSourceTransactionObject 对象返回
    Object transaction = doGetTransaction();

    // Cache debug flag to avoid repeated checks.
    boolean debugEnabled = logger.isDebugEnabled();

    // <2> 如果没有 @Transactional 注解对应的元信息,则创建一个默认的 TransactionDefinition 对象
    if (definition == null) {
        // Use defaults if no transaction definition given.
        definition = new DefaultTransactionDefinition();
    }

    // <3> 如果上面 `transaction` 数据源事务对象已有 Connection 连接,且正处于一个事务中,表示当前线程已经在一个事务中了
    if (isExistingTransaction(transaction)) {
        // Existing transaction found -> check propagation behavior to find out how to behave.
        // <3.1> 根据 Spring 事务传播级别进行不同的处理,同时创建一个 DefaultTransactionStatus 事务状态对象,包含以下信息:
        // TransactionDefinition 事务定义、DataSourceTransactionObject 数据源事务对象、
        // 是否需要新创建一个事务、是否需要一个新的事务同步器、被挂起的事务资源对象
        return handleExistingTransaction(definition, transaction, debugEnabled);
    }

    // <4> 否则,当前线程没有事务

    // 超时不能小于默认值
    if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
        throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
    }

    // <4.1> 如果是 **MANDATORY** 事务传播级别(当前线程已经在一个事务中,则加入该事务,否则抛出异常),因为当前线程没有事务,此时抛出异常
    if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
        throw new IllegalTransactionStateException(
                "No existing transaction found for transaction marked with propagation \'mandatory\'");
    }
    // <4.2> 否则,如果事务传播级别为 **REQUIRED|REQUIRES_NEW|NESTED**
    else if (
        // 如果当前线程已经在一个事务中,则加入该事务,否则新建一个事务(默认)
        definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
        // 无论如何都会创建一个新的事务,如果当前线程已经在一个事务中,则挂起当前事务,创建一个新的事务
        definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
        // 执行一个嵌套事务
        definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) 
    {
        // <4.2.1> 创建一个“空”的挂起资源对象
        SuspendedResourcesHolder suspendedResources = suspend(null);
        try {
            // 是否需要新的事务同步器,默认为 true
            boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
            // <4.2.2> 创建一个 DefaultTransactionStatus 事务状态对象,设置相关属性
            // 这里 `newTransaction` 参数为 `true`,表示是一个新的事务
            DefaultTransactionStatus status = newTransactionStatus(
                    definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
            // <4.2.3> 【关键】执行 begin 操作,如果没有 Connection 数据库连接,则通过 DataSource 创建一个新的连接
            // 设置 Connection 的隔离级别、是否只读,并执行 Connection#setAutoCommit(false) 方法,不自动提交
            // 同时将 DataSource(数据源对象)和 ConnectionHolder(数据库连接持有者)保存至 ThreadLocal 中
            doBegin(transaction, definition);
            // <4.2.4> 借助 TransactionSynchronizationManager 事务同步管理器设置相关 ThreadLocal 变量
            prepareSynchronization(status, definition);
            // <4.2.5> 返回上面创建的 DefaultTransactionStatus 事务状态对象
            return status;
        } catch (RuntimeException | Error ex) {
            resume(null, suspendedResources);
            throw ex;
        }
    }
    // <4.3> 否则,创建一个“空”的事务状态对象
    else {
        // Create "empty" transaction: no actual transaction, but potentially synchronization.
        if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
            logger.warn("Custom isolation level specified but no actual transaction initiated; " +
                    "isolation level will effectively be ignored: " + definition);
        }
        // 是否需要新的事务同步器,默认为 true
        boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
        // 创建一个 DefaultTransactionStatus 事务状态对象,设置相关属性,这里也是一个新的事务
        return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
    }
}

整个过程如下:

  1. 先从当前事务管理器中获取 DataSource 对象,然后尝试以它作为一个 Key 从一个 ThreadLocal 的 Map 中获取对应的 ConnectionHolder 连接对象(没有就是 null),最终包装成一个 DataSourceTransactionObject 对象返回

    // DataSourceTransactionManager.java
    @Override
    protected Object doGetTransaction() {
        DataSourceTransactionObject txObject = new DataSourceTransactionObject();
        txObject.setSavepointAllowed(isNestedTransactionAllowed());
        // 从事务同步管理器根据 DataSource 获取 Connection 连接持有者
        // 就是从它的 ThreadLocal 中获取
        ConnectionHolder conHolder =
                (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
        txObject.setConnectionHolder(conHolder, false);
        return txObject;
    }
    // TransactionSynchronizationManager.java
    /**
     * 事务资源,两种数据键值对
     * 1. 会话工厂和会话,SqlSessionFactory -> SqlSessionHolder
     * 2. 数据源和连接,DataSource -> ConnectionHolder
     */
    private static final ThreadLocal<Map<Object, Object>> resources =
            new NamedThreadLocal<>("Transactional resources");
    
  2. 如果没有 @Transactional 注解对应的元信息,则创建一个默认的 TransactionDefinition 对象

  3. 如果上面 transaction 数据源事务对象已有 Connection 连接,且正处于一个事务中,表示当前线程已经在一个事务中了

    // DataSourceTransactionManager.java
    @Override
    protected boolean isExistingTransaction(Object transaction) {
        // 获取这个数据源事务对象
        DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
        // 是否已有 Connection 连接,且正处于一个事务中
        return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive());
    }
    
    1. 调用 handleExistingTransaction(..) 方法,根据 Spring 事务传播级别进行不同的处理,同时创建一个 DefaultTransactionStatus 事务状态对象并返回
  4. 否则,当前线程没有事务

    1. 如果是 MANDATORY 事务传播级别(当前线程已经在一个事务中,则加入该事务,否则抛出异常),因为当前线程没有事务,此时抛出异常
    2. 否则,如果事务传播级别为 REQUIRED | REQUIRES_NEW | NESTED
      1. 创建一个“空”的被挂起的资源对象
      2. 创建一个 DefaultTransactionStatus 事务状态对象,设置相关属性,这里 newTransaction 参数为 true(记住),表示是一个新的事务
      3. 【关键】调用 doBegin(..) 方法,执行 begin 操作,如果没有 Connection 数据库连接,则通过 DataSource 创建一个新的连接;会设置 Connection 的隔离级别、是否只读,并执行 Connection#setAutoCommit(false) 方法,不自动提交;同时将 DataSource(数据源对象)和 ConnectionHolder(数据库连接持有者)保存至 ThreadLocal 中
      4. 借助 TransactionSynchronizationManager 事务同步管理器设置相关 ThreadLocal 变量,例如当前事务的隔离级别、是否只读、是否处于事务中等
      5. 返回上面创建的 DefaultTransactionStatus 事务状态对象
    3. 否则,创建一个“空”的事务状态对象
      1. 创建一个 DefaultTransactionStatus 事务状态对象,不使用事务

整个处理过程稍微有点复杂,不过流程非常清晰,当没有事务时,根据事务的传播级别决定是否需要创建一个事务,创建过程主要在上面的第 4.2.3 步;当正处于一个事务中时,在 3.1 步,根据事务的传播级别判断是否需要创建一个新的事务,或者加入该事务等操作;接下来我们来看看这两种情况

1.2 doBegin 方法

doBegin(..) 方法,创建一个新的事务,如下:

// AbstractPlatformTransactionManager.java
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
    Connection con = null;

    try {
        // <1> 如果没有 Connection 数据库连接,或者连接处于事务同步状态
        if (!txObject.hasConnectionHolder() ||
                txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
            // <1.1> 通过 DataSource 创建一个 Connection 数据库连接
            Connection newCon = obtainDataSource().getConnection();
            if (logger.isDebugEnabled()) {
                logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
            }
            // <1.2> 重置 ConnectionHolder 连接持有者,封装刚创建的数据库连接
            txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
        }

        // <2> 设置ConnectionHolder 连接持有者处于事务同步中
        txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
        // <3> 获取 Connection 数据库连接
        con = txObject.getConnectionHolder().getConnection();

        // <4> 设置 Connection 是否只读和事务隔离性
        Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
        // <5> 保存之前的事务隔离级别(被挂起的事务)
        txObject.setPreviousIsolationLevel(previousIsolationLevel);

        // Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
        // so we don\'t want to do it unnecessarily (for example if we\'ve explicitly
        // configured the connection pool to set it already).
        // <6> 将自动提交关闭
        if (con.getAutoCommit()) {
            txObject.setMustRestoreAutoCommit(true);
            if (logger.isDebugEnabled()) {
                logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
            }
            con.setAutoCommit(false);
        }

        // <7> 如果需要强制设置只读(默认不需要),且连接本身是只读的,则这里提前设置事务的只读性
        prepareTransactionalConnection(con, definition);
        // <8> 当前 Connection 数据库连接正处于一个事务中
        txObject.getConnectionHolder().setTransactionActive(true);

        // <9> 设置超时时间
        int timeout = determineTimeout(definition);
        if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
            txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
        }

        // Bind the connection holder to the thread.
        // <10> 如果是新的事务,则将 DataSource(数据源对象)和 ConnectionHolder(数据库连接持有者)保存至 ThreadLocal 中
        if (txObject.isNewConnectionHolder()) {
            TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
        }
    }
    catch (Throwable ex) {
        if (txObject.isNewConnectionHolder()) {
            DataSourceUtils.releaseConnection(con, obtainDataSource());
            txObject.setConnectionHolder(null, false);
        }
        throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
    }
}

过程如下:

  1. 如果没有 Connection 数据库连接,或者连接处于事务同步状态
    1. 通过 DataSource 创建一个 Connection 数据库连接
    2. 重置 ConnectionHolder 连接持有者,封装刚创建的数据库连接
  2. 设置 ConnectionHolder 连接持有者处于事务同步中
  3. 获取 Connection 数据库连接,设置是否只读、事务隔离性、超时时间,并将 autocommit 设置为 fasle,不自动提交
  4. 保存之前的事务隔离级别(被挂起的事务)
  5. 如果需要强制设置只读(默认不需要),且连接本身是只读的,则这里提前设置事务的只读性
  6. 设置当前 ConnectionHolder 数据库连接正处于一个事务中
  7. 如果是新的事务,则将 DataSource(数据源对象)和 ConnectionHolder(数据库连接持有者)保存至 ThreadLocal 中

整个过程关键在于第 3 步将 autocommit 设置为 false,不会自动提交,这样一来,可以在一个事务中根据行为作出相应的操作,例如出现异常进行回滚,没有问题则进行提交

接下来我们来看看 Spring 对于当前线程正处于一个事务中时,如何进行处理的

1.3 handleExistingTransaction 方法

handleExistingTransaction(..) 方法,处理已存在事务的情况,如下:

// AbstractPlatformTransactionManager.java
private TransactionStatus handleExistingTransaction(
        TransactionDefinition definition, Object transaction, boolean debugEnabled)
        throws TransactionException {

    // <1> 如果是 **NEVER** 事务传播级别,因为当前线程正处于一个事务中,此时抛出异常
    if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
        throw new IllegalTransactionStateException(
                "Existing transaction found for transaction marked with propagation \'never\'");
    }

    // <2> 否则,如果是 **NOT_SUPPORTED** 事务传播级别,因为当前线程正处于一个事务中,此时挂起事务
    if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
        // <2.1> 事务挂起,也就是从 ThreadLocal 中移除各种对象,并返回一个挂起的资源对象(包含所有被移除的对象)
        Object suspendedResources = suspend(transaction);
        // 是否需要一个创建一个事务同步器(默认为 true)
        boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
        // <2.2> 创建一个 DefaultTransactionStatus 事务状态对象,设置相关属性,包括被挂起的资源
        // 设置 `transaction` 为 null(当前没有事务),`newTransaction` 为 `false`,表示不是一个新的事务
        // 同时借助 TransactionSynchronizationManager 事务同步管理器设置相关 ThreadLocal 变量
        return prepareTransactionStatus(
                definition, null, false, newSynchronization, debugEnabled, suspendedResources);
    }

    // <3> 否则,如果是 **REQUIRES_NEW** 事务传播级别(无论如何都会创建一个新的事务),因为当前线程正处于一个事务中,此时挂起当前事务,创建一个新的事务
    if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
        // <3.1> 事务挂起,也就是从 ThreadLocal 中移除各种对象,并返回一个挂起的资源对象(包含所有被移除的对象)
        SuspendedResourcesHolder suspendedResources = suspend(transaction);
        try {
            // 是否需要一个创建一个事务同步器(默认为 true)
            boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
            // <3.2> 创建一个事务状态对象,设置相关属性,包括被挂起的资源
            // 设置 `newTransaction` 为 `true`,表示是一个新的事务
            DefaultTransactionStatus status = newTransactionStatus(
                    definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
            // <3.3> 【关键】执行 begin 操作,如果没有 Connection 数据库连接,则通过 DataSource 创建一个新的连接
            // 设置 Connection 的隔离级别、是否只读,并执行 Connection#setAutoCommit(false) 方法,不自动提交
            // 同时将 DataSource(数据源对象)和 ConnectionHolder(数据库连接持有者)保存至 ThreadLocal 中
            doBegin(transaction, definition);
            // <3.4> 借助 TransactionSynchronizationManager 事务同步管理器设置相关 ThreadLocal 变量
            prepareSynchronization(status, definition);
            // <3.5> 返回上面创建的 DefaultTransactionStatus 事务状态对象
            return status;
        }
        catch (RuntimeException | Error beginEx) {
            // 在抛出异常前唤醒刚才被挂起的资源
            resumeAfterBeginException(transaction,

以上是关于死磕Spring之AOP篇的主要内容,如果未能解决你的问题,请参考以下文章

死磕Spring AOP系列3:剖析Bean处理器之DefaultAdvisorAutoProxyCreator

死磕Spring AOP系列5:设计模式在AOP中的使用

死磕Spring AOP系列2:剖析Bean处理器之BeanNameAutoProxyCreator

死磕Spring AOP系列1:编程式实现AOP

阿里灵魂面试30道--死磕 Spring 之 IoC 篇

阿里灵魂面试30道--死磕 Spring 之 IoC 篇