百木园-与人分享,
就是让自己快乐。

Spring系列28:@Transactional事务源码分析

本文内容

  1. @Transactional事务使用

  2. @EnableTransactionManagement 详解

  3. @Transactional事务属性的解析

  4. TransactionInterceptor 事务控制

声明式事务使用和原理

声明式的主要步骤

  1. 使用@EnableTransactionManagement启用Spring 事务管理支持
  2. 使用@Transactional标识需要事务的方法会自动开启事务
  3. 注入数据源和事务管理器

下面通过案例演示一下上面的效果。

案例

  1. 使用@EnableTransactionManagement启用Spring 事务管理支持,配置类上需要有@Configuration注解

    @Configuration
    @ComponentScan
    @EnableTransactionManagement
    public class AppConfig {}
    
  2. 使用@Transactional标识需要事务的方法会自动开启事务。addUser方法需要事务

    @Service
    public class UserService {
    
        @Autowired
        private JdbcTemplate jdbcTemplate;
    
        @Transactional
        public void addUser() {
            System.out.println(\"执行前记录:\" + jdbcTemplate.queryForList(\"SELECT * from t_user\"));
            jdbcTemplate.update(\"insert into t_user (name) values (?)\", \"xx\");
            jdbcTemplate.update(\"insert into t_user (name) values (?)\", \"oo\");
            System.out.println(\"执行后记录:\" + jdbcTemplate.queryForList(\"SELECT * from t_user\"));
        }
    }
    
  3. 注入数据源和事务管理器

    @Configuration
    @ComponentScan
    @EnableTransactionManagement
    public class AppConfig {
    
        /**
         * 定义一个数据源
         * @return
         */
        @Bean
        public DataSource dataSource() {
            DruidDataSource dataSource = new DruidDataSource();
            dataSource.setDriverClassName(\"\");
            dataSource.setDriverClassName(\"com.mysql.jdbc.Driver\");
            dataSource.setUrl(\"jdbc:mysql://192.168.25.24:3306/xxx?characterEncoding=UTF-8\");
            dataSource.setUsername(\"root\");
            dataSource.setPassword(\"xxx\");
            return dataSource;
        }
    
        /**
         * 定义一个JdbcTemplate来执行sql
         * @param dataSource
         * @return
         */
        @Bean
        public JdbcTemplate jdbcTemplate(DataSource dataSource) {
            return new JdbcTemplate(dataSource);
        }
    
        /**
         * 定义一个管理器
         * @param dataSource
         * @return
         */
        @Bean
        public PlatformTransactionManager transactionManager(DataSource dataSource) {
            return new DataSourceTransactionManager(dataSource);
        }
    }
    
  4. 测试程序

    public class DeclarativeTest {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context =
                    new AnnotationConfigApplicationContext(AppConfig.class);
            UserService userService = context.getBean(UserService.class);
            userService.addUser();
            context.close();
        }
    }
    

    输出结果如下:

    执行前记录:[{id=1, name=test1-1}, {id=2, name=test1-2}, {id=3, name=xx}, {id=4, name=oo}, {id=5, name=xx}, {id=6, name=oo}]
    执行后记录:[{id=1, name=test1-1}, {id=2, name=test1-2}, {id=3, name=xx}, {id=4, name=oo}, {id=5, name=xx}, {id=6, name=oo}, {id=7, name=xx}, {id=8, name=oo}]	
    

原理

@EnableTransactionManagement注解会开启Spring自动管理事务的功能。开启之后在Spring容器启动的过程中,会拦截所有bean的创建过程,判断bean 是否需要让Spring来管理事务,如果需要那么通过aop的方式创建代理对象。代理中会添加一个拦截器TransactionInterceptor,拦截@Trasaction标识方法的执行,在方法执行前后添加事务的功能。

下面进行源码分析,需要用到的前置只是是Spring Aop相关知识和编程式事务管理的知识,前面的文章有涉及,提前看一下。

@EnableTransactionManagement 详解

@EnableTransactionManagement 会开启Spring的事务管理功能,查看下源码。

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

   /**
    * 指示是否创建基于子类(CGLIB)的代理(true),而不是标准的基于Java接口的代理(false)。默认为false。
    * 仅当mode()设置为AdviceMode.PROXY时适用。
    */
   boolean proxyTargetClass() default false;

   /**
    * 指示应该如何应用事务通知。 默认值是AdviceMode.PROXY。
    * 请注意,代理模式只允许通过代理拦截调用。同一类内的本地调用不会被拦截;
    * 在本地调用中,对这种方法的Transactional注释将被忽略,因为Spring的拦截器甚至不会在这样的运行时场景中起作用。
    */
   AdviceMode mode() default AdviceMode.PROXY;

   /**
    * 当在特定连接点上应用多个通知时,指示事务顾问程序的执行顺序。 默认值是Ordered.LOWEST_PRECEDENCE
    */
   int order() default Ordered.LOWEST_PRECEDENCE;

}

3个参数属性值

  • proxyTargetClass : 指示是否创建基于子类(CGLIB)的代理(true),而不是标准的基于Java接口的代理(false)
  • mode:指示应该如何应用事务通知。 默认值是AdviceMode.PROXY。
  • order: 当在特定连接点上应用多个通知时,指示事务顾问程序的执行顺序。 默认值是Ordered.LOWEST_PRECEDENCE,最后处理事务拦截器。

TransactionManagementConfigurationSelector

重点是@Import(TransactionManagementConfigurationSelector.class),注入一些事务相关的bean到Spring容器中进行事务的管理控制。

根据EnableTransactionManagement的mode值选择应该使用AbstractTransactionManagementConfiguration的哪个实现。

package org.springframework.transaction.annotation;

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {

   /**
    * 此处是AdviceMode的作用,默认是用代理,另外一个是ASPECTJ
    */
   @Override
   protected String[] selectImports(AdviceMode adviceMode) {
      switch (adviceMode) {
         case PROXY:
             // @1
            return new String[] {AutoProxyRegistrar.class.getName(),
                  ProxyTransactionManagementConfiguration.class.getName()};
         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);
   }

}

我们的mode是 AdviceMode.PROXY ,所以走@1位置,注入AutoProxyRegistrarProxyTransactionManagementConfiguration

AutoProxyRegistrar注入 InfrastructureAdvisorAutoProxyCreator

AutoProxyRegistrar的作用是注入一个InfrastructureAdvisorAutoProxyCreator,用于拦截bean的创建过程,为需要的事务控制的bean 创建代理对象,这个类非常关键,后面详细讲。

public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
   public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
      boolean candidateFound = false;
      Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
      // 遍历所有注解,找到有mode和proxyTargetClass的注解
      for (String annType : annTypes) {
         AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
         if (candidate == null) {
            continue;
         }
         Object mode = candidate.get(\"mode\");
         Object proxyTargetClass = candidate.get(\"proxyTargetClass\");
         if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
               Boolean.class == proxyTargetClass.getClass()) {
            candidateFound = true;
            if (mode == AdviceMode.PROXY) {
               // 注册aop InfrastructureAdvisorAutoProxyCreator 不展开
               AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
               // 强制设置proxyTargetClass=true后面使用cglib
               if ((Boolean) proxyTargetClass) {
                  AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
                  return;
               }
            }
         }
      }
   }

}

ProxyTransactionManagementConfiguration

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

   @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
   @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
   public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
         TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {

      BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
      advisor.setTransactionAttributeSource(transactionAttributeSource);
      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(TransactionAttributeSource transactionAttributeSource) {
      TransactionInterceptor interceptor = new TransactionInterceptor();
      interceptor.setTransactionAttributeSource(transactionAttributeSource);
      if (this.txManager != null) {
         interceptor.setTransactionManager(this.txManager);
      }
      return interceptor;
   }

}

ProxyTransactionManagementConfiguration 代理事务配置,注册事务需要用的一些类,而且Role=ROLE_INFRASTRUCTURE都是属于内部级别的,如下:

  • BeanFactoryTransactionAttributeSourceAdvisor 事务属性通知器,存放事务注解的方法相关的属性
  • TransactionAttributeSource事务属性源,就是事务注解的一些属性,也用来解析事务注解属性,实际是AnnotationTransactionAttributeSource
  • TransactionInterceptor事务拦截器,该类包含与Spring底层事务API的集成。TransactionInterceptor简单地以正确的顺序调用相关的超类方法,比如invokeWithinTransaction。这个类非常关键,负责事务相关的AOP增强的。

小结

EnableTransactionManagement注解的作用主要注入了InfrastructureAdvisorAutoProxyCreator负责拦截bean的创建过程为特定的bean创建代理对象,并通过TransactionInterceptor事务拦截器来实现方法的事务控制。

@Transactional 详解

该注解用于描述单个方法或类上的事务属性。在类级别,该注释作为默认值应用于声明类及其子类的所有方法。注意,类级别它并不适用于类层次结构上的父类,也就是父类方法需要在本地重新声明,以便参与子类级别的注释。

注解的属性的语义的具体信息,由 TransactionDefinitionTransactionAttribute 提供。

package org.springframework.transaction.annotation;

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {

   @AliasFor(\"transactionManager\")
   String value() default \"\";

   /**
    * 用来确定目标事务管理器bean
    */
   @AliasFor(\"value\")
   String transactionManager() default \"\";

   /**
    * 事务传播类型
    */
   Propagation propagation() default Propagation.REQUIRED;

   /**
    * 事务隔离级别
    */
   Isolation isolation() default Isolation.DEFAULT;

   /**
    * 事务超时
    */
   int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;

   /**
    * 只读事务
    */
   boolean readOnly() default false;

   /**
    * 指定哪些异常类型必须导致事务回滚,指定Throwable的子类型;默认只回滚RuntimeException和Error
    */
   Class<? extends Throwable>[] rollbackFor() default {};

   /**
    * 指示哪些异常类型必须导致事务回滚,这里异常类名称
    */
   String[] rollbackForClassName() default {};

   /**
    * 指定哪些异常不进行回滚
    */
   Class<? extends Throwable>[] noRollbackFor() default {};

   /**
    * 指定哪些异常类型不进行回滚,异常类型名称
    */
   String[] noRollbackForClassName() default {};

}

@Transactional注解如何解析成事务属性

AnnotationTransactionAttributeSource类

image-20220217100026551

从类图看我们关注AnnotationTransactionAttributeSource通过SpringTransactionAnnotationParser@Transcation转成事务属性供Spring事务处理使用。

  1. 如果@Transcation注解配置了属性,转换成RuleBasedTransactionAttribute
  2. 如果@Transcation注解没有配置属性,转换成DefaultTransactionAttribute,只有在抛出RuntimeExceptionError时候才回滚

按照Spring源码设计设计的一般套路我们看下右侧的TransactionAttributeSource 接口和抽象类AbstractFallbackTransactionAttributeSource

TransactionAttributeSource 接口

public interface TransactionAttributeSource {

   /**确定给定的类是否是TransactionAttributeSource元数据格式的事务属性的候选类*/
   default boolean isCandidateClass(Class<?> targetClass) {
      return true;
   }

   /**解析给定方法的@Transaction事务属性,如果方法是非事务性的,则返回null*/
   @Nullable
   TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass);

}

AbstractFallbackTransactionAttributeSource类

先看getTransactionAttribute()方法

public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
   // 判断method所在的class是不是Object类型
   if (method.getDeclaringClass() == Object.class) {
      return null;
   }

   // First, see if we have a cached value.
   // 构建缓存key
   Object cacheKey = getCacheKey(method, targetClass);
   // 从缓存中获取 @1
   TransactionAttribute cached = this.attributeCache.get(cacheKey);
   // 有缓存,不会每次computeTransactionAttribute
   if (cached != null) {
      // Value will either be canonical value indicating there is no transaction attribute,
      // or an actual transaction attribute.
      // 判断缓存中的对象是不是空事务属性的对象
      if (cached == NULL_TRANSACTION_ATTRIBUTE) {
         return null;
      }
      else {
         // 存在就直接返回事务属性
         return cached;
      }
   }
   else {
      // We need to work it out.
      // 查找我们的事务注解
      TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
      // Put it in the cache.
      // 若解析出来的事务注解属性为空
      if (txAttr == null) {
         // 往缓存中存放空事务注解属性
         this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
      }
      else {
         // 我们执行方法的描述符:包名+类名+方法名
         String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
         // 把方法描述设置到事务属性上去
         if (txAttr instanceof DefaultTransactionAttribute) {
            ((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
         }
         if (logger.isTraceEnabled()) {
            logger.trace(\"Adding transactional method \'\" + methodIdentification + \"\' with attribute: \" + txAttr);
         }
         // 加入缓存
         this.attributeCache.put(cacheKey, txAttr);
      }
      return txAttr;
   }
}

缓存中有类对应方法的事务属性就直接返回,没有就先解析@1再缓存起来。

computeTransactionAttribute方法

protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
   // Don\'t allow no-public methods as required.
   // 首先判断方法是否是public,默认是支持public的
   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代表实现类中的方法
   Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);

   // First try is the method in the target class.
   // 优先方法上解析的事务注解的属性,会去找父类或者接口的方法
   TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
   if (txAttr != null) {
      return txAttr;
   }

   // Second try is the transaction attribute on the target class.
   // 如果没有,再尝试声明该方法的类上注解属性,会去父类或者接口找
   txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
   if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
      return txAttr;
   }

   // 如果指定方法不等于方法
   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;
}

查找事务属性的查找顺序如下:

  1. 特定的目标方法,会去找父类或者接口的方法
  2. 目标类,会去找父类或者接口
  3. 声明的方法
  4. 声明方法所在的类

AnnotationTransactionAttributeSource#determineTransactionAttribute() 方法委托给SpringTransactionAnnotationParser解析给定类或是方法上的@Transactional注解的事务属性

protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
   // 获取我们的注解解析器
   for (TransactionAnnotationParser parser : this.annotationParsers) {
      // 通过注解解析器去解析我们的元素(方法或者类)上的注解
      TransactionAttribute attr = parser.parseTransactionAnnotation(element);
      if (attr != null) {
         return attr;
      }
   }
   return null;
}

接下来看下是如何解析和包装的SpringTransactionAnnotationParser#parseTransactionAnnotation()方法。

public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
   // 从element对象中获取@Transactional注解,然后把注解属性封装到了AnnotationAttributes
   AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
         element, Transactional.class, false, false);
   if (attributes != null) {
      // 解析出真正的事务属性对象
      return parseTransactionAnnotation(attributes);
   }
   else {
      return null;
   }
}

分析2个点:

  • AnnotatedElementUtils.findMergedAnnotationAttributes()负责解析目标类或目标方法上的@Transactional,会向上找父类或是接口的
  • parseTransactionAnnotation()方法包装成TransactionAttribute

看下是如何包装转换的。

protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {

   // 创建一个基础规则的事务属性对象
   RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();

   // 解析@Transactionl上的传播行为
   Propagation propagation = attributes.getEnum(\"propagation\");
   rbta.setPropagationBehavior(propagation.value());
   // 解析@Transactionl上的隔离级别
   Isolation isolation = attributes.getEnum(\"isolation\");
   rbta.setIsolationLevel(isolation.value());
   // 解析@Transactionl上的事务超时事件
   rbta.setTimeout(attributes.getNumber(\"timeout\").intValue());
   // 解析readOnly
   rbta.setReadOnly(attributes.getBoolean(\"readOnly\"));
   // 解析@Transactionl上的事务管理器的名称
   rbta.setQualifier(attributes.getString(\"value\"));

   List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
   // 解析针对哪种异常回滚
   for (Class<?> rbRule : attributes.getClassArray(\"rollbackFor\")) {
      rollbackRules.add(new RollbackRuleAttribute(rbRule));
   }
   // 对哪种异常进行回滚
   for (String rbRule : attributes.getStringArray(\"rollbackForClassName\")) {
      rollbackRules.add(new RollbackRuleAttribute(rbRule));
   }
   // 对哪种异常不回滚
   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已经很清晰了。

如何自动生成代理对象

这部分和之前的声明式AOP的源码分析是一样的过程,通过类图过一下。

image-20220217105749202

  1. 谁负责创建代理?

    InfrastructureAdvisorAutoProxyCreator继承我们熟悉的AbstractAdvisorAutoProxyCreator类,是个BeanPostProcessor,在Spring容器启动的过程中,会拦截bean的创建过程,为需要事务支持的bean生成代理对象。

  2. 谁负责判断bean是否需要代理?

    BeanFactoryTransactionAttributeSourceAdvisor是个Advisor,组合了切点和通知。哪些bean需要代理满足增强由切点TransactionAttributeSourcePointcut来通过TransactionAttributeSource来判定bean的类或是方法上是否有@Transactional注解。

  3. 谁负责实际的事务增强工作?

    TransactionInterceptor 继承MethodInterceptor是个拦截器,负责拦截代理对象目标方法,在前后增加事务控制的逻辑。这个类下面进行详细分析。

TransactionInterceptor 如何进行事务控制

TransactionInterceptor类

Spring中声明式事务时通过AOP的方式实现的,事务方法的执行最终都会由TransactionInterceptor invoke()拦截增强的。

package org.springframework.transaction.interceptor;
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
   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属性
      Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

      // Adapt to TransactionAspectSupport\'s invokeWithinTransaction...
      /**
       * 以事务的方式调用目标方法
       * 在这埋了一个钩子函数 用来回调目标方法的
       */
      return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
   }

事务的实现是委托给TransactionAspectSupport父类实现的。

TransactionAspectSupport类

invokeWithinTransaction() 方法

基于环绕通知的实现事务控制,委托给该类上的其他几个模板方法,其实里面主要内容就是编程式的事务控制了。这是个模板方法,主要功能点如下:

  • 如何获取事务管理器对象
  • 通过事务管理器开启事务
  • 执行目标方法
  • 方法异常如何完成事务
  • 正常返回如何完成事务提交
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
      final InvocationCallback invocation) throws Throwable {
   // 获取我们的事务属性源对象
   TransactionAttributeSource tas = getTransactionAttributeSource();
   // 通过事务属性源对象获取到当前方法的事务属性信息
   final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
   // @1获取我们配置的事务管理器对象
   final TransactionManager tm = determineTransactionManager(txAttr);
   PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
   // 获取连接点的唯一标识  类名+方法名
   final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

   // 声明式事务处理
   if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
      // @2创建TransactionInfo
      TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

      Object retVal;
      try {
         // 执行被增强方法,调用具体的处理逻辑
         retVal = invocation.proceedWithInvocation();
      }
      catch (Throwable ex) {
         //@3 异常回滚 如何走?可能只需提交,也可能只需回滚,这个取决于事务的配置
         completeTransactionAfterThrowing(txInfo, ex);
         throw ex;
      }
      finally {
         //清除事务信息,恢复线程私有的老的事务信息
         cleanupTransactionInfo(txInfo);
      }

      //成功后提交,会进行资源储量,连接释放,恢复挂起事务等操作
      commitTransactionAfterReturning(txInfo);
      return retVal;
   }
}
determineTransactionManager() 事务管理器获取

查找和获取的顺序是:

  1. 先看@Transactional中是否通过value或者transactionManager指定了事务管理器
  2. TransactionInterceptor.transactionManagerBeanName是否有值,如果有,将通过这个值查找事务管理器
  3. TransactionInterceptor.transactionManager是否有值,如果有则返回,这个是通过容器TransactionManagementConfigurer接口设置到TransactionInterceptor中的
  4. 如果上面3种都没有,将从Spring容器中查找TransactionManager类型的作为默认事务管理器
protected TransactionManager determineTransactionManager(@Nullable TransactionAttribute txAttr) {
   // Do not attempt to lookup tx manager if no tx attributes are set
   // txAttr == null || this.beanFactory == null ,返回拦截器中配置的事务管理器
   if (txAttr == null || this.beanFactory == null) {
      return getTransactionManager();
   }

   //qualifier就是@Transactional注解中通过value或者transactionManager来指定事务管理器的bean名称
   String qualifier = txAttr.getQualifier();
   if (StringUtils.hasText(qualifier)) {
      //从spring容器中查找[beanName:qualifier,type:TransactionManager]的bean
      return determineQualifiedTransactionManager(this.beanFactory, qualifier);
   }
   else if (StringUtils.hasText(this.transactionManagerBeanName)) {
      //从spring容器中查找[beanName:this.transactionManagerBeanName,type:TransactionManager]的bean
      return determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName);
   }
   else {
      //最后通过类型TransactionManager在spring容器中找事务管理器
      TransactionManager defaultTransactionManager = getTransactionManager();
      if (defaultTransactionManager == null) {
         defaultTransactionManager = this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);
         if (defaultTransactionManager == null) {
            defaultTransactionManager = this.beanFactory.getBean(TransactionManager.class);
            this.transactionManagerCache.putIfAbsent(
                  DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
         }
      }
      return defaultTransactionManager;
   }
}
createTransactionIfNecessary() 创建并开启事务
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
      @Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
   // 如果没有名称指定则使用方法唯一标识,并使用DelegatingTransactionAttribute封装txAttr
   if (txAttr != null && txAttr.getName() == null) {
      txAttr = new DelegatingTransactionAttribute(txAttr) {
         @Override
         public String getName() {
            return joinpointIdentification;
         }
      };
   }

   TransactionStatus status = null;
   if (txAttr != null) {
      if (tm != null) {
         // @1获取TransactionStatus事务状态信息
         status = tm.getTransaction(txAttr);
      }
   }
   // @2根据指定的属性与status准备一个TransactionInfo,
   return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}

分析如下:

  • @1获取TransactionStatus事务状态信息,也就是是编程式事务的创建和开启。
  • @2TransactionInfo生成

prepareTransactionInfo() 方法创建事务信息并绑定到当前线程

protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm,
      @Nullable TransactionAttribute txAttr, String joinpointIdentification,
      @Nullable TransactionStatus status) {

   // 创建事务信息
   TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
   if (txAttr != null) {
      // The transaction manager will flag an error if an incompatible tx already exists.
      // 设置新事务状态
      txInfo.newTransactionStatus(status);
   }

   // 事务信息绑定到当前线程
   txInfo.bindToThread();
   return txInfo;
}

事务信息是有哪些内容?简单过一下内部类TransactionInfo

/**
 * 用于保存事务信息的不透明对象。子类必须将其传递回该类的方法,但不能看到其内部
 */
protected static final class TransactionInfo {
       /** 事务管理器 */
   @Nullable
   private final PlatformTransactionManager transactionManager;
    /** 事务属性 */
   @Nullable
   private final TransactionAttribute transactionAttribute;
    /** 切点标识名 */
   private final String joinpointIdentification;
    /** 事务状态 */
   @Nullable
   private TransactionStatus transactionStatus;
       /** 旧的事务信息 */
   @Nullable
   private TransactionInfo oldTransactionInfo;
    
    /**
		 * 绑定新事务到当前线程,旧的会被保存
		 */
    private void bindToThread() {
        this.oldTransactionInfo = transactionInfoHolder.get();
        transactionInfoHolder.set(this);
    }

    /**
		 * 恢复线程中旧事务信息
		 */
    private void restoreThreadLocalStatus() {
        transactionInfoHolder.set(this.oldTransactionInfo);
    }    

}
completeTransactionAfterThrowing() 异常后完成事务
/**
 * 如果支持回滚的话就进行回滚,否则就处理提交,提交里面如果TransactionStatus.isRollbackOnly()=true的话也会进行回滚处理
 */
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);
      }
      // @1判断事务是否需要回滚
      if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
         try {
            // 进行回滚
            txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
         }
      }
      else {
         // We don\'t roll back on this exception.
         // Will still roll back if TransactionStatus.isRollbackOnly() is true.
         try {
            // @2通过事务管理器提交事务
            txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
         }
      }
   }
}

异常后如果匹配上我们@Transaction指定的异常类型,在调用事务管理器进行事务回滚,否则通过事务管理器进行提交事务。

commitTransactionAfterReturning 正常完成事务

通过事务管理器进行事务提交。

protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
   if (txInfo != null && txInfo.getTransactionStatus() != null) {
      txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
   }
}
小结

TransactionInterceptor 对事务控制包括开启、提交、回滚等操作,其实都是通过事务管理器进行的,这和编程式事务管理是一样的。

总结

本文进行了Spring中@Transactional声明事务的源码解析,结合了声明式AOP的源码分析和编程式事务管理的源码分析。总结下过程是就是通过BeanPostProcessor拦截bean创建过程自动创建代理对象,通过TransactionInterceptor 环绕通知增强目标方法,在目标方法执行前后增加事务的控制逻辑。

知识分享,转载请注明出处。学无先后,达者为先!


来源:https://www.cnblogs.com/kongbubihai/p/16082281.html
本站部分图文来源于网络,如有侵权请联系删除。

未经允许不得转载:百木园 » Spring系列28:@Transactional事务源码分析

相关推荐

  • 暂无文章