Loading

Spring声明式事务的工作原理

Spring事务管理Java后端项目开发中都会用到的一个技术点,每个Java工程师都必须精通。

Spring事务管理可以分为两类:

  • 声明式事务管理
  • 编程式事务管理

声明式事务管理只需要在代码中添加@Transactional注解,即可自动进行事务管理。由于使用方便,是项目开发中的首选。

在Spring Boot中,只要我们引入了相关依赖,就会自动开启声明式事务功能。

例如,我们引入mybatis-spring-boot-starter,它会自动引入spring-tx等相关依赖,并且自动开启事务功能:

<dependency>  
   <groupId>org.mybatis.spring.boot</groupId>  
   <artifactId>mybatis-spring-boot-starter</artifactId>  
</dependency>

Spring Boot的声明式事务的工作原理如上图,总的来说经过三个步骤:

  1. TransactionAutoConfiguration为核心,基于Spring Boot自动配置机制,创建事务相关bean。对于声明式事务来说,它会开启@EnableTransactionManagement注解。
  2. @EnableTransactionManager会使用@Import注解引入TransactionManagementConfigurationSelector,然后开启基于代理或Aspectj的声明式事务功能。
  3. 对于基于代理的声明式事务,ProxyTransactionManagementConfiguration会创建基于@Transactional注解的Advisor。在bean实例化过程中,AOP功能会根据该Advisor对相关bean进行代理。

1 TransactionAutoConfiguration

TransactionAutoConfiguration会对事务功能进行自动配置,与声明式事务相关的源码如下:

@AutoConfiguration  
@ConditionalOnClass(PlatformTransactionManager.class)  
@EnableConfigurationProperties(TransactionProperties.class)  
public class TransactionAutoConfiguration {  
   @Configuration(proxyBeanMethods = false)  
   @ConditionalOnBean(TransactionManager.class)  
   @ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)  
   public static class EnableTransactionManagementConfiguration {  
  
      @Configuration(proxyBeanMethods = false)  
      @EnableTransactionManagement(proxyTargetClass = false)  
      @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false")  
      public static class JdkDynamicAutoProxyConfiguration {  
      }  
  
      @Configuration(proxyBeanMethods = false)  
      @EnableTransactionManagement(proxyTargetClass = true)  
      @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",  
            matchIfMissing = true)  
      public static class CglibAutoProxyConfiguration {  
      }  
   }  
}

首先,TransactionAutoConfiguration标注了三个注解:

  • @AutoConfiguration:表示TransactionAutoConfiguration可以作为配置类被Spring Boot自动配置。
  • @ConditionalOnClass(PlatformTransactionManager.class):表示只有存在PlatformTransactionManager类时,Spring容器才会注册TransactionAutoConfiguration
  • @EnableConfigurationProperties(TransactionProperties.class):表示读取配置文件中的spring.transaction属性。

然后,根据配置文件中的spring.aop属性,会分别引入JdkDynamicAutoProxyConfiguration或CglibAutoProxyConfiguration(默认)配置类。

这两个配置类都是空的,它们的作用其实是标注@EnableTransactionManagement注解。

2 @EnableTransactionManagement

@EnableTransactionManagement注解表示开启声明式事务管理功能:

@Target(ElementType.TYPE)  
@Retention(RetentionPolicy.RUNTIME)  
@Documented  
@Import(TransactionManagementConfigurationSelector.class)  
public @interface EnableTransactionManagement {  
   boolean proxyTargetClass() default false;  
   AdviceMode mode() default AdviceMode.PROXY;  
   int order() default Ordered.LOWEST_PRECEDENCE;  
}

它的作用是通过@Import注解引入TransactionManagementConfigurationSelector,然后根据AdviceMode分别开启基于proxyaspectj的声明式事务管理功能(注册对应的配置类):

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {  
   protected String[] selectImports(AdviceMode adviceMode) {  
      // 根据adviceMode开启声明式事务管理功能
      switch (adviceMode) {  
         case PROXY:  
            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);  
   }  
  
}

3 ProxyTransactionManagementConfiguration

ProxyTransactionManagementConfiguration的核心作用就是创建声明式事务管理的Advisor,AOP会根据它对bean进行动态代理:

@Configuration(proxyBeanMethods = false)  
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)  
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {  
   // 注册Advisor
   @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;  
   }  
  
   // 注册@Transactional的pointcut解析数据源
   @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;  
   }  
}

3.1 @Transactional解析器

AnnotationTransactionAttributeSource中定义了对@Transactional等注解的解析规则:

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());  
   }  
}

例如,SpringTransactionAnnotationParser可以判断bean是否标注@Transactional注解:

public boolean isCandidateClass(Class<?> targetClass) {  
   return AnnotationUtils.isCandidateClass(targetClass, Transactional.class);  
}

也可以获取@Transactional的属性信息:

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());  
   String timeoutString = attributes.getString("timeoutString");  
   Assert.isTrue(!StringUtils.hasText(timeoutString) || rbta.getTimeout() < 0,  
         "Specify 'timeout' or 'timeoutString', not both");  
   rbta.setTimeoutString(timeoutString);  
  
   rbta.setReadOnly(attributes.getBoolean("readOnly"));  
   rbta.setQualifier(attributes.getString("value"));  
   rbta.setLabels(Arrays.asList(attributes.getStringArray("label")));  
  
   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;  
}

3.2 事务方法拦截器

TransactionInterceptor中定义了事务方法的执行逻辑,TransactionInterceptor#invoke()

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<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);  
  
   // Adapt to TransactionAspectSupport's invokeWithinTransaction...  
   return invokeWithinTransaction(invocation.getMethod(), targetClass, new CoroutinesInvocationCallback() {  
      @Override  
      @Nullable      
      public Object proceedWithInvocation() throws Throwable {  
         return invocation.proceed();  
      }  
      @Override  
      public Object getTarget() {  
         return invocation.getThis();  
      }  
      @Override  
      public Object[] getArguments() {  
         return invocation.getArguments();  
      }  
   });  
}

TransactionAspectSupport#invokeWithinTransaction()中会根据@Transactional注解信息执行创建事务/加入事务,执行业务方法,提交事务/回滚等流程:

protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,  
      final InvocationCallback invocation) throws Throwable {  
  
   // 获取事务属性信息,例如@Transactional注解的属性  
   TransactionAttributeSource tas = getTransactionAttributeSource();  
   final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);  
   
   // 获取事务管理器
   final TransactionManager tm = determineTransactionManager(txAttr);  
  
   // ReactiveTransactionManager事务管理器执行流程(一般跳过)
   if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {  
      // 省略……
   }  
  
   // PlatformTransactionManager事务管理器执行流程
   PlatformTransactionManager ptm = asPlatformTransactionManager(tm);  
   final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);  
  
   // DataSourceTransactionManager或JtaTransactionManager等事务管理器执行流程
   if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {  
      // 获取事务信息:根据@Transactional注解信息创建事务/加入事务等 
      TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);  
  
      Object retVal;  
      try {  
         // 执行业务方法
         retVal = invocation.proceedWithInvocation();  
      }  
      catch (Throwable ex) {  
         // 业务方法抛异常,根据@Transactional注解信息进行回滚或提交
         completeTransactionAfterThrowing(txInfo, ex);  
         throw ex;  
      }  
      finally {  
         // 重置当前线程的事务信息
         cleanupTransactionInfo(txInfo);  
      }  
  
      if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {  
         // Set rollback-only in case of Vavr failure matching our rollback rules...  
         TransactionStatus status = txInfo.getTransactionStatus();  
         if (status != null && txAttr != null) {  
            retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);  
         }  
      }  
  
      // 如果当前事务仍存在,提交事务
      commitTransactionAfterReturning(txInfo);  
      return retVal;  
   }  
  
   // CallbackPreferringPlatformTransactionManager(WebSphereUowTransactionManager)事务管理器执行流程(一般跳过)
   else {  
      // 省略……
   }  
}

3.3 BeanFactoryTransactionAttributeSourceAdvisor

BeanFactoryTransactionAttributeSourceAdvisor定义了声明式事务管理的切面信息,核心包括:

  • 判断bean对象是否需要进行声明式事务代理:pointcuttransactionAttributeSourceAnnotationTransactionAttributeSource)。
  • 声明式事务的拦截逻辑:advice(具体逻辑查看TransactionInterceptor

首先,通过TransactionAttributeSourcePointcut#matches()可以判断是否需要进行声明式事务代理:

public boolean matches(Method method, Class<?> targetClass) {  
   // AnnotationTransactionAttributeSource对象
   TransactionAttributeSource tas = getTransactionAttributeSource();  
   // 解析@Transactional注解信息
   return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);  
}

通过AbstractFallbackTransactionAttributeSource#getTransactionAttribute()方法解析@Transactional注解信息:

public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {  
   if (method.getDeclaringClass() == Object.class) {  
      return null;  
   }  
  
   // 获取缓存
   Object cacheKey = getCacheKey(method, targetClass);  
   TransactionAttribute cached = this.attributeCache.get(cacheKey);  
   if (cached != null) {  
      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 dta = (DefaultTransactionAttribute) txAttr;  
            dta.setDescriptor(methodIdentification);  
            dta.resolveAttributeStrings(this.embeddedValueResolver);  
         }   
         this.attributeCache.put(cacheKey, txAttr);  
      }  
      return txAttr;  
   }  
}

AbstractFallbackTransactionAttributeSource#computeTransactionAttribute()

protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {  
   // Don't allow non-public methods, as configured.  
   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);  
  
   // 解析方法中的@Transactional信息,会调用SpringTransactionAnnotationParser#parseTransactionAnnotation()方法
   TransactionAttribute txAttr = findTransactionAttribute(specificMethod);  
   if (txAttr != null) {  
      return txAttr;  
   }  
  
   // 解析类中的@Transactinal信息,会调用SpringTransactionAnnotationParser#parseTransactionAnnotation()方法
   txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());  
   if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {  
      return txAttr;  
   }  
  
   // 对method/method.getDeclaringClass()进行解析
   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;  
}
posted @ 2023-02-08 17:57  Xianuii  阅读(867)  评论(0编辑  收藏  举报