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 環繞通知增強目標方法,在目標方法執行前后增加事務的控制邏輯。

知識分享,轉載請注明出處。學無先后,達者為先!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM