Spring 源码阅读 74:事务管理的原理 - BeanFactoryTransactionAttributeSourceAdvisor 分析

news2025/7/18 8:37:20

本文通过对 BeanFactoryTransactionAttributeSourceAdvisor 类的分析,了解了 Spring 是如何通过 AOP 来完成事务的管理的,本文的内容需要你对 Spring 的 AOP 的实现原理有一定的了解。

基于 Spring Framework v5.2.6.RELEASE

概述

Spring 的事务管理基于 AOP 特性,因此,事务管理的增强逻辑需要一个 Advisor 来提供,这便是 BeanFactoryTransactionAttributeSourceAdvisor,本文我们来分析它的原理。

类关系

它是 PointcutAdvisor 的实现类,我们开发时配置的切面通过 Spring 解析后得到的也是一个 PointcutAdvisor,因此,它们的原理应该是相似的。所以,本文会通过以下几个方面来进行分析:

  1. Spring 创建它的具体过程
  2. 如何匹配被增强的类型
  3. 如何匹配被增强的方法
  4. 通过增强逻辑实现事务管理的具体原理

创建

它是在 Spring 解析配置的时候被创建的,以下是 ProxyTransactionManagementConfiguration 中创建 BeanFactoryTransactionAttributeSourceAdvisor 的方法。

// org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor
@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;
}
复制代码

方法中,通过无参构造方法创建了 BeanFactoryTransactionAttributeSourceAdvisor 对象,并初始化了一些属性。它并没有显式地声明构造方法,因此我们分别来看几个属性的设置。

transactionAttributeSource 属性

transactionAttributeSource 属性的值,来自方法参数,需要 Spring 来注入,这个值的来源是同一个配置类中的另外一个方法。

// org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration#transactionAttributeSource
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
   return new AnnotationTransactionAttributeSource();
}
复制代码

其中,AnnotationTransactionAttributeSource 的构造方法如下。

public AnnotationTransactionAttributeSource() {
   this(true);
}
复制代码

再进入另外一个构造方法。

public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
   this.publicMethodsOnly = publicMethodsOnly;
   if (jta12Present || ejb3Present) {
      this.annotationParsers = new LinkedHashSet<>(4);
      this.annotationParsers.add(new SpringTransactionAnnotationParser());
      if (jta12Present) {
         this.annotationParsers.add(new JtaTransactionAnnotationParser());
      }
      if (ejb3Present) {
         this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
      }
   }
   else {
      this.annotationParsers = Collections.singleton(new SpringTransactionAnnotationParser());
   }
}
复制代码

AnnotationTransactionAttributeSource 的构造方法中,主要初始化了两个属性。

  • publicMethodsOnly 的值,从上一段代码的方法调用this(true)传入,它的值是true
  • annotationParsers 是一个列表,根据当前类加载器能够加载到的类型,添加不同的事物注解解析器,限于本文讨论的范围,我们只考虑 SpringTransactionAnnotationParser。

advice 属性

advice 属性的值,同样来自方法参数,它包含的是 Advisor 的增强逻辑,这里注入的值是 TransactionInterceptor 类型,来源也是用一配置类中的另一个方法。

// org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration#transactionInterceptor
@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;
}
复制代码

它的构造方法也不包含任何逻辑,并且,注入了上一部分介绍了 transactionAttributeSource。除此之外,如果成员变量txManager不为空,则赋值给他的 transactionManager 属性。

transactionManager 是事务管理器,可以在当前配置类的父类中,找到它的来源。

TransactionManager

以下就是初始化成员变量txManager的方法。

@Autowired(required = false)
void setConfigurers(Collection<TransactionManagementConfigurer> configurers) {
   if (CollectionUtils.isEmpty(configurers)) {
      return;
   }
   if (configurers.size() > 1) {
      throw new IllegalStateException("Only one TransactionManagementConfigurer may exist");
   }
   TransactionManagementConfigurer configurer = configurers.iterator().next();
   this.txManager = configurer.annotationDrivenTransactionManager();
}
复制代码

方法添加了 @Autowired 注解,参数是 TransactionManagementConfigurer 类型的集合,Spring 会找到容器中所有的该类型的 Bean,组成一个集合,作为参数执行这个方法的逻辑。

当方法传入的集合中有且只有一个元素的时候,它的annotationDrivenTransactionManager会被执行,并将的到的结果赋值给txManager

以下是 TransactionManagementConfigurer 接口的定义。

public interface TransactionManagementConfigurer {
TransactionManager annotationDrivenTransactionManager();
}
复制代码

里面只有一个方法,返回 TransactionManager 类型的结果,一个配置类可以通过实现 TransactionManagementConfigurer 接口来自定义 TransactionManager 的创建逻辑。

pointcut 属性

除了配置方法中设置的值以外,BeanFactoryTransactionAttributeSourceAdvisor 还有一个定义了初始值的属性pointcut,它表示切入点,负责匹配目标类和目标方法。

// org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor#pointcut
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
   @Override
   @Nullable
   protected TransactionAttributeSource getTransactionAttributeSource() {
      return transactionAttributeSource;
   }
};
复制代码

pointcut属性的类型是 TransactionAttributeSourcePointcut,并在初始化时实现了getTransactionAttributeSource方法。

进入 TransactionAttributeSourcePointcut 的构造方法。

// org.springframework.transaction.interceptor.TransactionAttributeSourcePointcut#TransactionAttributeSourcePointcut
protected TransactionAttributeSourcePointcut() {
   setClassFilter(new TransactionAttributeSourceClassFilter());
}
复制代码

构造方法中调用了setClassFilter方法给classFilter成员变量赋值,值是一个通过构造方法创建的 TransactionAttributeSourceClassFilter 类型的实例。

TransactionAttributeSourceClassFilter 是 TransactionAttributeSourcePointcut 的内部类,以下是它的源码。

private class TransactionAttributeSourceClassFilter implements ClassFilter {

   @Override
   public boolean matches(Class<?> clazz) {
      if (TransactionalProxy.class.isAssignableFrom(clazz) ||
            PlatformTransactionManager.class.isAssignableFrom(clazz) ||
            PersistenceExceptionTranslator.class.isAssignableFrom(clazz)) {
         return false;
      }
      TransactionAttributeSource tas = getTransactionAttributeSource();
      return (tas == null || tas.isCandidateClass(clazz));
   }
}
复制代码

我们都知道,在 Advisor 中,pointcut的主要作用是匹配目标类型和方法,以上的 ClassFilter 给 TransactionAttributeSourcePointcut 提供了一个类型匹配的具体逻辑。

在通过 Pointcut 进行目标类型和方法的匹配时,会先从 Pointcut 中获取一个 ClassFilter 或 MethodMatcher,然后通过它们的matches方法来判断。

TransactionAttributeSourcePointcut 中,获取 ClassFilter 和 MethodMatcher 的方法定义在其父类 StaticMethodMatcherPointcut 中。

@Override
public ClassFilter getClassFilter() {
   return this.classFilter;
}

@Override
public final MethodMatcher getMethodMatcher() {
   return this;
}
复制代码

其中,ClassFilter 就是在构造方法中初始化的 TransactionAttributeSourceClassFilter,而 MethodMatcher 就是其自身。

下面分别来看一下,它是如何做目标类和方法的匹配的。

目标类型匹配

目标类型的匹配逻辑在 TransactionAttributeSourceClassFilter 类的matches方法中。

// org.springframework.transaction.interceptor.TransactionAttributeSourcePointcut.TransactionAttributeSourceClassFilter#matches
@Override
public boolean matches(Class<?> clazz) {
   if (TransactionalProxy.class.isAssignableFrom(clazz) ||
         PlatformTransactionManager.class.isAssignableFrom(clazz) ||
         PersistenceExceptionTranslator.class.isAssignableFrom(clazz)) {
      return false;
   }
   TransactionAttributeSource tas = getTransactionAttributeSource();
   return (tas == null || tas.isCandidateClass(clazz));
}
复制代码

首先,确保目标类型不是 TransactionalProxy、PlatformTransactionManager 或者 PersistenceExceptionTranslator,然后,通过getTransactionAttributeSource方法,获取到transactionAttributeSource属性,通过他的isCandidateClass方法来判断。

// org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#isCandidateClass
@Override
public boolean isCandidateClass(Class<?> targetClass) {
   for (TransactionAnnotationParser parser : this.annotationParsers) {
      if (parser.isCandidateClass(targetClass)) {
         return true;
      }
   }
   return false;
}
复制代码

isCandidateClass方法的逻辑,就是遍历annotationParsers集合中的每一个 TransactionAnnotationParser 元素,执行过它们的isCandidateClass方法,进行判断。

根据之前的分析,我们这里只考虑集合中包含 SpringTransactionAnnotationParser 的情况,以下是它的isCandidateClass方法。

// org.springframework.transaction.annotation.SpringTransactionAnnotationParser#isCandidateClass
@Override
public boolean isCandidateClass(Class<?> targetClass) {
   return AnnotationUtils.isCandidateClass(targetClass, Transactional.class);
}
复制代码

再进入 AnnotationUtils 的isCandidateClass方法。

// org.springframework.core.annotation.AnnotationUtils#isCandidateClass(java.lang.Class<?>, java.lang.Class<? extends java.lang.annotation.Annotation>)
public static boolean isCandidateClass(Class<?> clazz, Class<? extends Annotation> annotationType) {
   return isCandidateClass(clazz, annotationType.getName());
}

// org.springframework.core.annotation.AnnotationUtils#isCandidateClass(java.lang.Class<?>, java.lang.String)
public static boolean isCandidateClass(Class<?> clazz, String annotationName) {
   if (annotationName.startsWith("java.")) {
      return true;
   }
   if (AnnotationsScanner.hasPlainJavaAnnotationsOnly(clazz)) {
      return false;
   }
   return true;
}
复制代码

如果类的名称是java.开头的,则返回true。然后,再 AnnotationsScanner 的hasPlainJavaAnnotationsOnly方法判断,除了此方法返回true的类型,其余情况都返回true

// org.springframework.core.annotation.AnnotationsScanner#hasPlainJavaAnnotationsOnly(java.lang.Class<?>)
static boolean hasPlainJavaAnnotationsOnly(Class<?> type) {
   return (type.getName().startsWith("java.") || type == Ordered.class);
}
复制代码

名称以java.开头的情况前面已经判断过了,因此这里就是判断类型是否是 Ordered 类型。

总结下来,匹配类的逻辑就是,确保类不是 TransactionalProxy、PlatformTransactionManager、PersistenceExceptionTranslator、Ordered 这几种类型之一。

目标方法匹配

方法的匹配逻辑在 TransactionAttributeSourcePointcut 的matches方法中。

@Override
public boolean matches(Method method, Class<?> targetClass) {
   TransactionAttributeSource tas = getTransactionAttributeSource();
   return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}
复制代码

匹配的逻辑依然是通过成员变量transactionAttributeSourcegetTransactionAttribute方法,从方法获取事务相关的注解配置属性信息,如果获取到的结果不为空,则符合匹配条件。

AnnotationTransactionAttributeSource 中的getTransactionAttribute方法,继承自父类 AbstractFallbackTransactionAttributeSource。

// org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#getTransactionAttribute
@Override
@Nullable
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
   if (method.getDeclaringClass() == Object.class) {
      return null;
   }

   // First, see if we have a cached value.
   Object cacheKey = getCacheKey(method, targetClass);
   TransactionAttribute cached = this.attributeCache.get(cacheKey);
   if (cached != null) {
      // Value will either be canonical value indicating there is no transaction attribute,
      // or an actual transaction attribute.
      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;
   }
}
复制代码

首先判断方法不是在 Object 类中声明的,然后,从缓存中读取数据,如果缓存中没有数据,则执行获取注解配置信息的逻辑。因此,这个方法中重点要分析的逻辑是最外层的else语句块中的逻辑。

方法最终返回的txAttr是通过computeTransactionAttribute方法得到的,无论获取到的txAttr是否为空,都会将其添加到缓存集合attributeCache中,并最终作为结果返回。

computeTransactionAttribute的源码如下。

// org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#computeTransactionAttribute
@Nullable
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
   // Don't allow no-public methods as required.
   if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
      return null;
   }

   // The method may be on an interface, but we need attributes from the target class.
   // If the target class is null, the method will be unchanged.
   Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);

   // First try is the method in the target class.
   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. 如果事务注解只对public修饰的方法有效,但是当前的目标方法method不是public修饰的方法,直接返回空。
  2. 通过 AopUtils 的getMostSpecificMethod方法,获取目标方法method的具体实现方法,也就是说,如果当前的目标方法是一个接口中定义的方法,则根据当前目标类型获取到类型中的实现方法specificMethod
  3. 通过findTransactionAttribute方法从specificMethod获取 TransactionAttribute,如果不为空,则作为结果返回。
  4. 通过findTransactionAttribute方法从specificMethod所在的类型获取 TransactionAttribute,如果不为空,则作为结果返回。
  5. 如果methodspecificMethod不是同一个方法,则对method和它所在的类型执行3、4步的操作。
  6. 以上都得不到结果的情况下,返回空。

上面的步骤中,获取 TransactionAttribute 的findTransactionAttribute方法被多次调用,它的定义如下。

// org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#findTransactionAttribute(java.lang.Class<?>)
@Override
@Nullable
protected TransactionAttribute findTransactionAttribute(Class<?> clazz) {
   return determineTransactionAttribute(clazz);
}

// org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#findTransactionAttribute(java.lang.reflect.Method)
@Override
@Nullable
protected TransactionAttribute findTransactionAttribute(Method method) {
   return determineTransactionAttribute(method);
}
复制代码

其中的具体逻辑交给了determineTransactionAttribute方法。

// org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#determineTransactionAttribute
@Nullable
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
   for (TransactionAnnotationParser parser : this.annotationParsers) {
      TransactionAttribute attr = parser.parseTransactionAnnotation(element);
      if (attr != null) {
         return attr;
      }
   }
   return null;
}
复制代码

主要的逻辑就是遍历annotationParsers集合中的注解解析器,来解析参数中传入的 AnnotatedElement,来获取 TransactionAttribute。前面我们提到过,这里的注解解析器,我们只考虑 SpringTransactionAnnotationParser,因此,进入它的parseTransactionAnnotation方法。

// org.springframework.transaction.annotation.SpringTransactionAnnotationParser#parseTransactionAnnotation(java.lang.reflect.AnnotatedElement)
@Override
@Nullable
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
   AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
         element, Transactional.class, false, false);
   if (attributes != null) {
      return parseTransactionAnnotation(attributes);
   }
   else {
      return null;
   }
}
复制代码

逻辑非常简单,就是获取到方法或者类上的 Transactional 注解,然后将注解的属性封装成一个 TransactionAttribute 并返回。

总结下来就是,如果目标方法或者所在的类型,标记了 Transactional 注解,那么就会被负责事务管理的拦截器匹配到,并对其进行增强。

增强逻辑

了解了目标类型和方法的匹配,最后在看具体的增强逻辑。根据 Spring AOP 的机制,执行增强逻辑时,需要从 BeanFactoryTransactionAttributeSourceAdvisor 对象中,通过getAdvice方法,获取到增强逻辑的拦截器,再执行拦截器的invoke方法。

前文中已经介绍过,BeanFactoryTransactionAttributeSourceAdvisor 的advice属性是在配置类中初始化的,它的类型是 TransactionInterceptor,它的主要继承关系如下。

可以确认,它实现了 MethodInterceptor 接口,并且它的invoke方法,就是增强逻辑所在的方法。

// org.springframework.transaction.interceptor.TransactionInterceptor#invoke
@Override
@Nullable
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, invocation::proceed);
}
复制代码

其中的核心逻辑是调用了定义在父类 TransactionAspectSupport 中的invokeWithinTransaction方法。

先分析方法的参数。其中,methodtargetClass是目标方法和类型,相比起来,更值得注意的是第三个参数invocation,它的类型是 InvocationCallback。

// org.springframework.transaction.interceptor.TransactionAspectSupport.InvocationCallback
@FunctionalInterface
protected interface InvocationCallback {

   Object proceedWithInvocation() throws Throwable;
}
复制代码

InvocationCallback 是一个函数式接口,其中的proceedWithInvocation方法,返回了一个 Object 结果。在调用方法时,这里传入的值是invocation::proceed,也就是说,这里的invocation参数传入的是目标方法的调用。了解完参数后,再看方法体。

这个方法的代码超过了 100 行,我们只分析其中的核心部分,完整的方法体代码可以到 TransactionAspectSupport 类的源码中查看。

// org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction

// If the transaction attribute is null, the method is non-transactional.
TransactionAttributeSource tas = getTransactionAttributeSource();
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
final TransactionManager tm = determineTransactionManager(txAttr);

// 省略部分代码

PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
   // Standard transaction demarcation with getTransaction and commit/rollback calls.
   TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

   Object retVal;
   try {
      // This is an around advice: Invoke the next interceptor in the chain.
      // This will normally result in a target object being invoked.
      retVal = invocation.proceedWithInvocation();
   }
   catch (Throwable ex) {
      // target invocation exception
      completeTransactionAfterThrowing(txInfo, ex);
      throw ex;
   }
   finally {
      cleanupTransactionInfo(txInfo);
   }

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

// 省略部分代码
复制代码

方法体中的内容,可以归纳为以下几个关键步骤:

  • 通过createTransactionIfNecessary方法,得到一个 TransactionInfo 类型的txInfo对象。从方法名称和返回的结果来看,这一步应该是根据需要创建了事务,并得到事务的信息。
  • 然后,在try语句中调用目标方法,并的到执行的返回值retVal
  • 如果执行目标方法的过程中出现了异常,则执行completeTransactionAfterThrowing方法,处理异常的情况,再将异常抛出。
  • 在finally语句块中执行cleanupTransactionInfo方法,清除异常信息。
  • 如果上述过程中没有出现异常,则执行commitTransactionAfterReturning方法,提交事务。

从上述归纳中可以看出,最主要的步骤都是通过调用相应的方法来完成的,接下来,我们就逐一分析这些方法。

createTransactionIfNecessary 方法

// org.springframework.transaction.interceptor.TransactionAspectSupport#createTransactionIfNecessary
@SuppressWarnings("serial")
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
      @Nullable TransactionAttribute txAttr, final String joinpointIdentification) {

   // If no name specified, apply method identification as transaction name.
   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) {
         status = tm.getTransaction(txAttr);
      }
      else {
         if (logger.isDebugEnabled()) {
            logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
                  "] because no transaction manager has been configured");
         }
      }
   }
   return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
复制代码

其中,有一行关键的代码,如下:

status = tm.getTransaction(txAttr);
复制代码

这里对执行tmgetTransaction方法,获取食物状态,开启事务也是在这里完成的。tm的类型是 PlatformTransactionManager,它是一个事务管理器对象。事务管理器是在 Spring 的事务管理配置类中注册到 Spring 容器的,这一部分在前文已经介绍过。

事务管理器中会通过 JDBC 的方式,获取到数据库连接对象 Connection,通过调用setAutoCommit(false)将自动提交设置为false,就开启了事务。

目标方法的执行

开启事务之后,就可以开始执行目标方法了,由于目标方法执行时抛出的异常可能会导致事务会滚,因此,目标方法的调用被放在了try语句块中,方便对抛出的一场进行处理。

completeTransactionAfterThrowing 方法

如果目标方法跑出了一场,则会交给catch语句块中的completeTransactionAfterThrowing方法来处理。

// org.springframework.transaction.interceptor.TransactionAspectSupport#completeTransactionAfterThrowing
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);
      }
      if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
         try {
            txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
         }
         catch (TransactionSystemException ex2) {
            logger.error("Application exception overridden by rollback exception", ex);
            ex2.initApplicationException(ex);
            throw ex2;
         }
         catch (RuntimeException | Error ex2) {
            logger.error("Application exception overridden by rollback exception", ex);
            throw ex2;
         }
      }
      else {
         // We don't roll back on this exception.
         // Will still roll back if TransactionStatus.isRollbackOnly() is true.
         try {
            txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
         }
         catch (TransactionSystemException ex2) {
            logger.error("Application exception overridden by commit exception", ex);
            ex2.initApplicationException(ex);
            throw ex2;
         }
         catch (RuntimeException | Error ex2) {
            logger.error("Application exception overridden by commit exception", ex);
            throw ex2;
         }
      }
   }
}
复制代码

这个方法的源码虽然不少,但是逻辑其实非常简单。首先,会判断当前抛出的异常是不是属于 Transaction 注解中rollbackFor属性配置的异常的范畴,如果是,则说明当前抛出的异常,是需要回滚的异常,此时,就会调用事务管理器的rollback方法进行回滚,否则,通过commit方法进行提交,不过这里的提交并不是直接提交事务,而是在提交前会判断事务信息,只在符合提交条件的情况下进行提交。

cleanupTransactionInfo 方法

在目标方法执行的finally语句块中会cleanupTransactionInfo方法,从方法名称可以看出它的作用是清理事务信息。

// org.springframework.transaction.interceptor.TransactionAspectSupport#cleanupTransactionInfo
protected void cleanupTransactionInfo(@Nullable TransactionInfo txInfo) {
   if (txInfo != null) {
      txInfo.restoreThreadLocalStatus();
   }
}
复制代码

它的作用其实就是将 ThreadLocal 中保存的当前事务的信息恢复到当前事务开启之前的状态。

commitTransactionAfterReturning 方法

最后,commitTransactionAfterReturning方法负责事务的提交。

// org.springframework.transaction.interceptor.TransactionAspectSupport#commitTransactionAfterReturning
protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
   if (txInfo != null && txInfo.getTransactionStatus() != null) {
      if (logger.isTraceEnabled()) {
         logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
      }
      txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
   }
}
复制代码

走到这一步,说明前面的流程实行的都很顺利,因此,直接告诉事务管理器提交事务就可以了。

总结

本文通过对 BeanFactoryTransactionAttributeSourceAdvisor 类的分析,了解了 Spring 是如何通过 AOP 来完成事务的管理的,本文的内容需要你对 Spring 的 AOP 的实现原理有一定的了解。

由于本文的重点是 BeanFactoryTransactionAttributeSourceAdvisor 对提供事务管理功能的分析,遇到涉及太多 Spring 的事务抽象相关的内容,没有做介绍,如果你对此感兴趣,可以搜索相关的文章了解其中的细节。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/7020.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于 Flask-Admin 与 AdminLTE 构建通用后台管理系统

Flask-Admin 是什么&#xff1f; Flask-Admin 官网文档中给出了其功能定位&#xff1a; Why Flask-Admin? In a world of micro-services and APIs, Flask-Admin solves the boring problem of building an admin interface on top of an existing data model. With little e…

SAP 公司代码全局参数设置及其意义

在SAP中配置公司时&#xff0c;会配置公司的全局参数&#xff0c;但这些参数具体的意思是什么估计很多同学都搞不懂&#xff0c;我也找了下资料&#xff0c;贴出来供大家参考。 设置参数路径&#xff1a;IMG→财务会计→财务会计全局设置→公司代码的全球参数→输入全局参数 账…

教你几个手机识别图片中的文字小技巧

平时我们在工作&#xff0c;有时候会拿到需要录入的纸质文件&#xff0c;如果我们使用双手逐一对照录入的话&#xff0c;就太浪费时间了。其实还有一个更简单的方法&#xff0c;就是将需要录入的文件拍摄下来&#xff0c;借助工具将图片内容转写为文字出来&#xff0c;再将其复…

Python Flask框架-开发简单博客-认证蓝图

作者&#xff1a;Eason_LYC 悲观者预言失败&#xff0c;十言九中。 乐观者创造奇迹&#xff0c;一次即可。 一个人的价值&#xff0c;在于他所拥有的。可以不学无术&#xff0c;但不能一无所有&#xff01; 技术领域&#xff1a;WEB安全、网络攻防 关注WEB安全、网络攻防。我的…

最新定制的安卓项目及设计报告——仿番茄小说APP

已录演示视频&#xff0c;想看演示视频的可以私我 《移动应用开发实践》实践报告 APP名称&#xff1a; 番茄免费小说 要求&#xff1a; 格式&#xff1a;宋体&#xff0c;小四号字&#xff1b;首行缩进&#xff1b;行距&#xff1a;1.5倍。 每人独立完成Android App的设计…

三步学会如何构建平衡二叉树(简单好理解)

何为平衡二叉树? 首先回顾一下&#xff0c;什么是平衡二叉树&#xff08;亦被称为AVL树&#xff0c;Adelson-Velskii and Landis&#xff09;。平衡二叉树主要具有以下三个特点&#xff1a; 1. 平衡二叉树首先要符合搜索二叉树的特点&#xff1a;即左子树的值比根节点小&…

排序算法之归并排序

目录 归并排序递归实现 思想 图解 代码 归并排序的非递归版本 基本思想&#xff1a; 代码 归并排序递归实现 思想 最主要的相当于二叉树遍历中的后序遍历。 ①将数组分割成多个小区间&#xff08;当只有一个元素或者并不存在的时候就不用再分割了&#xff09; ②对每一…

某工控图片上传服务 CPU 爆高分析

一&#xff1a;背景 1.讲故事 今天给大家带来一个入门级的 CPU 爆高案例&#xff0c;前段时间有位朋友找到我&#xff0c;说他的程序间歇性的 CPU 爆高&#xff0c;不知道是啥情况&#xff0c;让我帮忙看下&#xff0c;既然找到我&#xff0c;那就用 WinDbg 看一下。 二&…

Linux进程概念和控制(必备知识)

文章目录1、冯诺依曼体系结构2、操作系统3、进程<1>进程的创建<2>进程查看<3>进程状态<4>进程优先级<5> 进程地址空间4、环境变量5、进程控制<1>进程终止<2>进程等待<3>进程替换1、冯诺依曼体系结构 我们常见的计算机&#x…

软考 - 软件工程

软件过程基本概述 基本要素 方法工具过程 软件过程模型 能力成熟度模型CMM 能力成熟度模型CMMI 统一过程UP模型 针对大型项目 三大特别 用例和风险驱动以架构为中心迭代并且增量 四个阶段 起始&#xff1a;确认需求和风险评估精化&#xff1a;核心架构设计构建&#xff1a;构…

Linux内核开发 | Linux内核目录结构分析(5.4.32)

文章目录1. arch2. block3. certs4. crypto5. Documentation6. drivers7. fs8. include9. init10. ipc11. kernel12. lib13. mm14. net15. samples16. scripts17. security18. sound19. tools20. usr21. virt本文以Linux主线5.4.32内核版本进行分析。1. arch 该目录下包含了li…

【ROS】机械人开发--ROS工作空间与功能包

机械人开发--ROS工作空间与功能包一、ROS工作空间1.1 概念1.2 创建工作空间1.3 编译工作空间1.4 设置环境变量1.5 添加环境变量二、功能包2.1 概念2.2 功能包的内容2.3 创建功能包三、CMakeLists.txt文件四、package.xml文件一、ROS工作空间 1.1 概念 工作空间&#xff08;wo…

以“新IT”助“数智融合”,联想推开“智能化转型”下半场的大门

作者 | 曾响铃 文 | 响铃说 近年来&#xff0c;我国对数字化的重视达到前所未有的高度&#xff0c;从“十四五”规划纲要首次将数字经济单独列为一篇&#xff1b;到二十大报告中指出&#xff1a;“坚持把发展经济的着力点放在实体经济上”、“促进数字经济和实体经济深度融合…

SpringMVC学习篇(五)

SpringMVC之json数据传递 1.1 准备工作 1.1.1 导入lombok依赖(方便写实体类) <dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.24</version></dependency>1.1.2 导入mvc js…

mysql经典案例带解析(你没见过的全新版本)55题

首先给出初始表格 表格创建命令 create table emp(id int primary key auto_increment,name varchar(20),job varchar(20),manager int,hiredate date,sal double(8,2),comm double(6,2),dept_id int)charsetutf8;create table dept(id int primary key auto_increment,nam…

AcrelEMS-BP生物制药工厂能效管理系统

安科瑞 华楠 聚焦全厂能源采集、监控、分析、调度,降本提效,实现企业双碳目标;致力于全域化设备监视、巡检、故障报警、工单管理,运维优化,提升设备使用效率。 综合自动化系统 110kV及以下变电站综合自动化系统实现遥测、遥信、遥控、事故追忆、故障录波、安全防护、上传调度 …

搭建接口平台YApi详解(含搭建node环境)

公司之前使用的doclever 感觉不太好用&#xff0c;打算私有化部署YApi 步骤 准备使用yapi的可视化部署&#xff0c;需要有node环境 安装node环境 测试一下有没有node环境 如下就是有 [root192 sbin]# node -v v14.17.0 [root192 sbin]# npm -v 6.14.13没有就创建 cd /us…

webpack5 打包环境抽离分环境基本配置

两种开发模式 开发模式&#xff1a;代码能编译自动化运行生产模式&#xff1a;代码编译优化输出Webpack 基本功能 开发模式&#xff1a;可以编译 ES Module 语法生产模式&#xff1a;可以编译 ES Module 语法&#xff0c;压缩 js 代码Webpack 配置文件5 个核心概念 entryoutput…

FL Studio21最新演示测试版本下载FL水果V21

FL Studio是市场上最受欢迎的音乐制作软件之一。它被世界各地的许多专业制作人和艺术家使用。FL Studio音乐软件的每日下载量超过40&#xff0c;000次&#xff0c;其增长是不断的&#xff0c;而且没有迹象表明很快就会放缓。随着新的 FL 产品版本在 Windows 和 Mac 上不断发布&…

25.gateway的Filter 过滤器工厂(springcloud)

1 概述 gateway 里面的过滤器和 Servlet 里面的过滤器&#xff0c;功能差不多&#xff0c;路由过滤器可以用于修改进入Http 请求和返回 Http 响应2 分类 2.1 按生命周期分两种 pre 在业务逻辑之前 post 在业务逻辑之后2.2 按种类分也是两种 GatewayFilter 需要配置某个路由&…