当前位置 博文首页 > 月圆吖:死磕Spring之AOP篇 - Spring 事务详解

    月圆吖:死磕Spring之AOP篇 - Spring 事务详解

    作者:月圆吖 时间:2021-05-12 18:22

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

    Spring 版本:5.1.14.RELEASE

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

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

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

    前序

    前面我的一系列文章对 Spring AOP 进行了比较详细的讲述,相信对于 Spring AOP 你有一个比较深入的理解,如果你不是很了解,建议先查看我前面的这一系列文章,因为 Spring 事务是借助于 Spring AOP 实现的。由于这段时间有点忙(太懒了~),没能及时更新 Spring AOP 在 Spring 内部的应用相关内容,趁着对它还有一点印象,我们一起来看看 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  >...</bean>
        <!-- 事务管理器 -->
        <bean  >
            <!-- 指定数据源 -->
            <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 这个类