• 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 环绕通知增强目标方法,在目标方法执行前后增加事务的控制逻辑。

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

  • 相关阅读:
    R语言使用caret包的featurePlot函数可视化变量的重要性、通过分组数据分布差异查看变量对于预测目标变量的判别性、通过可视化密度图进行判别分析
    torch.manual_seed()解析
    使用Ollama+OpenWebUI本地部署Gemma谷歌AI开放大模型完整指南
    【python学习】Day-023 正则表达式
    C++入门刷题练习(附代码、思路以及相关拓展)
    智能计算之粒子群算法(PSO)介绍
    基于springboot的社区流浪动物救助管理系统(前端+后端)
    深入浅出学习透析Nginx服务器的基本原理和配置指南「Keepalive性能分析实战篇」
    国内各大安卓应用市场的不同ASO优化点
    虹科分享 | 软件供应链攻击如何工作?如何评估软件供应链安全?
  • 原文地址:https://www.cnblogs.com/kongbubihai/p/16082281.html