SpringBoot源码解读与原理分析(三十三)SpringBoot整合JDBC(二)声明式事务的生效原理和控制流程

前言

SpringBoot整合JDBC的场景中,除了引入spring-jdbc,还会引入spring-tx实现事务控制。

SpringBoot源码解读与原理分析(三十二)SpringBoot整合JDBC(一)JDBC组件的自动装配 的示例项目中,在主启动类显式标注了@EnableTransactionManagement注解,用于开启注解声明式事务。但实际上,即便不进行标注,底层仍然会使用自动配置类的方式开启,也就是说SpringBoot默认开启注解声明式事务

具体的开启位置在自动配置类TransactionAutoConfiguration中。

10.3 声明式事务的生效原理

10.3.1 TransactionAutoConfiguration

源码1TransactionAutoConfiguration.java

@Configuration(proxyBeanMethods = false)
// ......
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",
                matchIfMissing = 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 {
    
        }
    
    }
}

由 源码1 可知,即使没有显式标注配置类@EnableTransactionManagement,底层的配置类EnableTransactionManagementConfiguration中也会进行开启。有些许不同的是,这里会根据项目中配置的AOP是否代理目标对象(proxyTargetClass的值)来决定创建哪种事务代理对象。

既然注解声明式事务的最终开关是@EnableTransactionManagement注解,那么这个注解的内部一定使用@Import注解导入了一些特殊的组件。

源码2EnableTransactionManagement.java

@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
    boolean proxyTargetClass() default false;
    AdviceMode mode() default AdviceMode.PROXY;
    int order() default Ordered.LOWEST_PRECEDENCE;
}

由 源码2 可知,@EnableTransactionManagement注解通过@Import注解导入了一个TransactionManagementConfigurationSelector,并且包含三个属性。

  • proxyTargetClass:该属性为true时,创建基于子类的代理(使用Cglib);该属性默认为false,即创建基于标准Java接口的代理。
  • order:优先级,默认为Ordered.LOWEST_PRECEDENCE。
  • mode:事务通知应用的模式。该属性的默认值为AdviceMode.PROXY,表示事务通知会在程序运行期间使用动态代理的方式向目标对象织入;该属性的另一个取值是AdviceMode.ASPECTJ,表示事务通知会在类加载期间向目标对象织入。

10.3.2 TransactionManagementConfigurationSelector

由类名可知,该组件是一个ImportSelector。

源码3TransactionManagementConfigurationSelector.java

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
    @Override
    protected String[] selectImports(AdviceMode adviceMode) {
        switch (adviceMode) {
            case PROXY:
                return new String[]{AutoProxyRegistrar.class.getName(),
                    ProxyTransactionManagementConfiguration.class.getName()};
            case ASPECTJ:
                return new String[]{determineTransactionAspectClass()};
            default:
                return null;
        }
    }
}

由 源码3 可知,该组件的selectImports方法会根据@EnableTransactionManagement注解的mode属性的值决定导入哪些组件。

当mode=PROXY时,导入AutoProxyRegistrar和ProxyTransactionManagementConfiguration两个组件。

10.3.3 AutoProxyRegistrar

源码4AutoProxyRegistrar.java

public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        boolean candidateFound = false;
        Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
        for (String annType : annTypes) {
            // 遍历类上标注的所有注解
            // 找到@EnableTransactionManagement注解
            AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
            if (candidate == null) {
                continue;
            }
            // 获取@EnableTransactionManagement注解的mode属性和proxyTargetClass属性
            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) {
                    // 当mode属性的值为PROXY,注册一个InfrastructureAdvisorAutoProxyCreator组件
                    AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
                    if ((Boolean) proxyTargetClass) {
                        // 当proxyTargetClass属性的值为true,强制AutoProxyCreator使用类代理
                        AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
                        return;
                    }
                }
            }
        }
        // ......
    }
}
源码5AopConfigUtils.java

public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
    return registerAutoProxyCreatorIfNecessary(registry, null);
}

public static BeanDefinition registerAutoProxyCreatorIfNecessary(
        BeanDefinitionRegistry registry, @Nullable Object source) {
    return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}

由 源码4-5 可知,AutoProxyRegistrar本身是一个ImportBeanDefinitionRegistrar,它的作用是向BeanDefinitionRegistrar中注册新的BeanDefinition。

从核心方法registerBeanDefinitions可以看出,AutoProxyRegistrar会根据@EnableTransactionManagement注解的mode属性和proxyTargetClass属性的值决定是否注册特定的组件。

默认情况下,mode属性的值为PROXY,因此registerBeanDefinitions方法会借助AopConfigUtils类注册一个InfrastructureAdvisorAutoProxyCreator组件。

在mode属性的值为PROXY前提下,如果proxyTargetClass属性的值为true,则会强制AutoProxyCreator使用类代理。

10.3.4 InfrastructureAdvisorAutoProxyCreator

源码6InfrastructureAdvisorAutoProxyCreator.java

public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator

由 源码6 可知,InfrastructureAdvisorAutoProxyCreator与AOP代理对象创建器AnnotationAwareAspectJAutoProxyCreator类似(详见 SpringBoot源码解读与原理分析(二十八)AOP模块的生命周期(一) 9.2 AnnotationAwareAspectJAutoProxyCreator),它们都继承了AbstractAdvisorAutoProxyCreator类,因此它们都可以创建代理对象。

查阅InfrastructureAdvisorAutoProxyCreator类的javadoc:

Auto-proxy creator that considers infrastructure Advisor beans only, ignoring any application-defined Advisors.
自动代理创建器只考虑基础类型的增强器,忽略任何应用程序自定义的增强器。

什么是“基础类型”?实际上是BeanDefinition中给Bean定义的3种角色:

源码7BeanDefinition.java

int ROLE_APPLICATION = 0;
int ROLE_SUPPORT = 1;
int ROLE_INFRASTRUCTURE = 2;

“基础类型”指的是BeanDefinition中的角色为ROLE_INFRASTRUCTURE。通常,只有SpringFramework内部定义的Bean才可能被标注为ROLE_INFRASTRUCTURE角色,而且这些Bean在应用程序中起到基础支撑的作用。

因此,可以得出以下结论:事务控制的核心是AOP中的一个MethodInterceptor,它的角色刚好是ROLE_INFRASTRUCTURE。InfrastructureAdvisorAutoProxyCreator在bean对象的初始化期间找到这个MethodInterceptor并包装为Advisor,给需要进行注解事务控制的bean对象构造代理对象。

值得注意的是,InfrastructureAdvisorAutoProxyCreator与AnnotationAwareAspectJAutoProxyCreator不会同时注册。由于AnnotationAwareAspectJAutoProxyCreator可以处理所有角色的通知,因此它的优先级更高,如果先注册了AnnotationAwareAspectJAutoProxyCreator,则不会再注册InfrastructureAdvisorAutoProxyCreator。

10.3.5 ProxyTransactionManagementConfiguration

TransactionManagementConfigurationSelector导入的另一个组件是ProxyTransactionManagementConfiguration配置类,其内部注册了3个与事务控制相关的核心组件。

10.3.5.1 TransactionAttributeSource
源码8ProxyTransactionManagementConfiguration.java

@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
    return new AnnotationTransactionAttributeSource();
}
源码9TransactionAttributeSource.java

public interface TransactionAttributeSource {
    default boolean isCandidateClass(Class<?> targetClass) {
		return true;
	}
	TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass);
}
源码10TransactionDefinition.java

public interface TransactionAttribute extends TransactionDefinition

由 源码8-10 可知,TransactionAttributeSource有一个getTransactionAttribute方法,该方法的javadoc如下:

Return the transaction attribute for the given method, or null if the method is non-transactional.
返回给定方法的事务属性,如果方法是非事务性的,则返回null。

可见,getTransactionAttribute方法将一个类中的方法解析并封装为TransactionAttribute,而TransactionAttribute本身又是一个TransactionDefinition,因此TransactionAttributeSource的作用就是将一个类中的方法解析并封装为一个事务定义信息TransactionDefinition

借助IDEA可以找到TransactionAttributeSource的几个实现类,其中一个是AnnotationTransactionAttributeSource类。

该类的javadoc如下:

Implementation of the org.springframework.transaction.interceptor.TransactionAttributeSourceinterface for working with transaction metadata in JDK 1.5+ annotation format.
实现了TransactionAttributeSource接口,用于处理 JDK 1.5+ 注释格式的事务元数据。
This class reads Spring’s JDK 1.5+ Transactional annotation.
这个类读取Spring的 JDK 1.5+ 的@Transactional注解。

这说明,AnnotationTransactionAttributeSource类解析事务信息的依据是@Transactional注解,这就是注解声明式事务的标注读取器。

至于是如何读取、解析的,详见 10.4 节。

10.3.5.2 TransactionInterceptor
源码11ProxyTransactionManagementConfiguration.java

@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;
}
源码12TransactionInterceptor.java

public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable
源码13TransactionAspectSupport.java

public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {
 
}

由 源码11-13 可知,TransactionInterceptor事务拦截器,本身是一个MethodInterceptor。

TransactionInterceptor还有一个父类TransactionAspectSupport,其内部集成了一些事务API,如执行事务的核心方法invokeWithinTransaction、创建事务、提交事务、回滚事务等。

至于是如何如何触发这些API的,详见 10.4 节。

10.3.5.3 BeanFactoryTransactionAttributeSourceAdvisor
源码14ProxyTransactionManagementConfiguration.java

@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);
    // 提取@EnableTransactionManagement注解的order属性
    if (this.enableTx != null) {
        advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
    }
    return advisor;
}
源码15BeanFactoryTransactionAttributeSourceAdvisor.java

public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
    @Nullable
    private TransactionAttributeSource transactionAttributeSource;
    
    private final TransactionAttributeSourcePointcut pointcut =     new TransactionAttributeSourcePointcut() {
            @Override
            @Nullable
            protected TransactionAttributeSource getTransactionAttributeSource() {
                return transactionAttributeSource;
            }
        };
}

由 源码14 可知,BeanFactoryTransactionAttributeSourceAdvisor是一个增强器,其内部组合了TransactionInterceptor事务拦截器和TransactionAttributeSource事务配置源。

由 源码15 可知,BeanFactoryTransactionAttributeSourceAdvisor的切入点就是TransactionAttributeSource,其判断一个类是否可以被增强的依据,就是利用TransactionAttributeSource检查一个类和方法是否标注@Transactional注解。

这个逻辑和实际项目开发中的事务控制逻辑是一样的,如果Service类或者方法上标注了@Transactional注解,则事务切面会介入控制。

10.4 声明式事务的控制流程

10.3 节研究了声明式事务的生效原理,本节以 10.1 节的整合项目案例,以Debug的方式研究声明式事务的控制流程。

10.4.1 CglibAopProxy#intercept()

默认情况下,@EnableTransactionManagement注解的proxyTargetClass属性的值为false,因此SpringBoot会使用代理目标类的方式创建代理对象,即CglibAopProxy的内部类DynamicAdvisedInterceptor 的intercept方法。

将断点打在intercept方法上,Debug运行项目可以得到下图:

CglibAopProxy#intercept()
可见,在intercept方法中,会调用getInterceptorsAndDynamicInterceptionAdvice方法获取要执行的增强器。而与声明式事务相关的增强器就是上面 10.3.5.3 节研究的BeanFactoryTransactionAttributeSourceAdvisor,这个增强器中组合的通知Advice,刚好是上面 10.3.5.2 节研究的TransactionInterceptor。

明确了通知Advice,则直接将断点打在TransactionInterceptor的invoke方法上。

10.4.2 TransactionInterceptor#invoke()

源码16TransactionInterceptor.java

public Object invoke(MethodInvocation invocation) throws Throwable {
    Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
    return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}

由 源码16 可知,TransactionInterceptor的invoke方法直接调用了invokeWithinTransaction方法,而该方法定义在TransactionInterceptor的父类TransactionAspectSupport中。

由于invokeWithinTransaction方法篇幅很长,下面拆解来看。

10.4.2.1 获取TransactionAttribute
源码17TransactionAspectSupport.java

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);
    // ......
}

由 源码17 可知,invokeWithinTransaction方法的第一步是利用TransactionAttributeSource获取TransactionAttribute,也就是事务定义信息。

源码18AbstractFallbackTransactionAttributeSource.java

private static final TransactionAttribute NULL_TRANSACTION_ATTRIBUTE = new DefaultTransactionAttribute() {
    @Override
    public String toString() {
        return "null";
    }
};

public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
    if (method.getDeclaringClass() == Object.class) {
        return null;
    }

    // 根据method和targetClass构造一个缓存key
    Object cacheKey = getCacheKey(method, targetClass);
    // 直接从缓存中获取TransactionAttribute
    TransactionAttribute cached = this.attributeCache.get(cacheKey);
    if (cached != null) {
        // 如果获取到的是NULL_TRANSACTION_ATTRIBUTE,则返回空
        if (cached == NULL_TRANSACTION_ATTRIBUTE) {
            return null;
        } else {
            // 如果获取到的不是空,则直接返回
            return cached;
        }
    } else {
        // 如果缓存中没有,则需要构造出来
        TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
        // 无论是否构造成功,都会放置到缓存attributeCache中
        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);
            }
            // logger...
            this.attributeCache.put(cacheKey, txAttr);
        }
        return txAttr;
    }
}

由 源码18 可知,getTransactionAttribute方法内部有一个缓存机制,首先会根据方法和方法所在的类去缓存中寻找TransactionAttribute,找到了直接返回,没找到则进行构造。若构造失败了,也会缓存一个NULL_TRANSACTION_ATTRIBUTE空定义并返回。

要注意的是,将断点打在getTransactionAttribute方法中,发现在解析UserService类的test方法时,从缓存中已经可以直接找到TransactionAttribute:

缓存中的TransactionAttribute不为空
这是因为,在创建事务代理对象时,事务通知Advice就需要与每个正在创建的bean对象进行匹配,而匹配时需要使用TransactionAttributeSource检查方法或方法所在类是否标注了@Transactional注解,以此来判断是否需要对当前正在创建的bean对象织入事务通知。

因此,在真正触发事务拦截器时,UserService类的test方法的TransactionAttribute就已经保存到缓存中了。

由 源码18 可知,如何解析和封装TransactionAttribute,使用的是computeTransactionAttribute方法。

源码19AbstractFallbackTransactionAttributeSource.java

protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
    // 非public方法不处理
    if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
        return null;
    }

    Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);

    // 首先寻找方法上是否标注了@Transaction注解
    TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
    if (txAttr != null) {
        return txAttr;
    }

    // 如果方法上没有,则寻找类上是否标注了@Transaction注解
    txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
    if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
        return txAttr;
    }

    // ......
    return null;
}

由 源码19 可知,解析和封装TransactionAttribute首先会寻找方法上是否标注了@Transaction注解,如果方法上没有,则寻找类上是否标注了@Transaction注解。

总结:当应用启动时,由于@EnableTransactionManagement注解默认生效,该注解会向IOC容器注册InfrastructureAdvisorAutoProxyCreator事务通知增强器,这个增强器会参与bean对象初始化的AOP后置处理逻辑,检查被创建的bean对象是否可以织入事务通知(标注@Transaction注解),检查的动作会同时将TransactionAttribute保存到AbstractFallbackTransactionAttributeSource的缓存中。因此在真正触发事务拦截器的逻辑而需要取出事务定义信息时,可以直接从缓存中取出而不需要重新解析。

10.4.2.2 获取TransactionManager
源码20TransactionAspectSupport.java

protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
        final InvocationCallback invocation) throws Throwable {
    // 获取TransactionAttribute ......
    
    // 获取TransactionManager
    final TransactionManager tm = determineTransactionManager(txAttr);
    // ......
}

protected TransactionManager determineTransactionManager(@Nullable TransactionAttribute txAttr) {
    if (txAttr == null || this.beanFactory == null) {
        return getTransactionManager();
    }

    String qualifier = txAttr.getQualifier();
    if (StringUtils.hasText(qualifier)) {
        return determineQualifiedTransactionManager(this.beanFactory, qualifier);
    } else if (StringUtils.hasText(this.transactionManagerBeanName)) {
        return determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName);
    } else {
        TransactionManager defaultTransactionManager = getTransactionManager();
        if (defaultTransactionManager == null) {
            defaultTransactionManager = this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);
            if (defaultTransactionManager == null) {
                // 最终从BeanFactory中通过getBean方法获取
                defaultTransactionManager = this.beanFactory.getBean(TransactionManager.class);
                this.transactionManagerCache.putIfAbsent(
                        DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
            }
        }
        return defaultTransactionManager;
    }
}

由 源码20 可知,获取到事务定义信息之后,接下来是获取事务管理器,调用的是determineTransactionManager方法,该方法用各种方式获取事务管理器,如果都没有获取到,最终会从BeanFactory中通过getBean方法获取。

在此处打断点可以发现,最终得到一个基于数据源的DataSourceTransactionalManager。

得到一个基于数据源的DataSourceTransactionalManager

10.4.2.3 响应式事务管理器的处理
源码21TransactionAspectSupport.java

protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
        final InvocationCallback invocation) throws Throwable {
    // 获取TransactionAttribute ......
    // 获取TransactionManager ......
    
    // 响应式事务管理器的处理
    if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
        ReactiveTransactionSupport txSupport = this.transactionSupportCache.computeIfAbsent(method, key -> {
            if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && TransactionAspectSupport.KotlinDelegate.isSuspend(method)) {
                // throw ......
            }
            ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(method.getReturnType());
            if (adapter == null) {
                // throw ......
            }
            return new ReactiveTransactionSupport(adapter);
        });
        return txSupport.invokeWithinTransaction(
                method, targetClass, invocation, txAttr, (ReactiveTransactionManager) tm);
    }
    // ......
}

由 源码21 可知,下一部分逻辑针对响应式事务。上一步返回的事务管理器的类型是DataSourceTransactionalManager,因此tm instanceof ReactiveTransactionManager的结果是false,不会进入响应式事务的处理逻辑。

10.4.2.4 事务控制的核心
源码22TransactionAspectSupport.java

protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
        final InvocationCallback invocation) throws Throwable {
    // 获取TransactionAttribute ......
    // 获取TransactionManager ......
    // 响应式事务管理器的处理 ......
    
    // 事务控制的核心
    PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
    final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

    if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
        // 1.开启事务
        TransactionAspectSupport.TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

        Object retVal;
        try {
            // 2.环绕通知,执行Service方法
            // This will normally result in a target object being invoked.
            retVal = invocation.proceedWithInvocation();
        } catch (Throwable ex) {
            // 3.捕捉到异常,回滚事务
            completeTransactionAfterThrowing(txInfo, ex);
            throw ex;
        } finally {
            cleanupTransactionInfo(txInfo);
        }

        if (retVal != null && vavrPresent && TransactionAspectSupport.VavrDelegate.isVavrTry(retVal)) {
            TransactionStatus status = txInfo.getTransactionStatus();
            if (status != null && txAttr != null) {
                retVal = TransactionAspectSupport.VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
            }
        }
        //4.提交事务
        commitTransactionAfterReturning(txInfo);
        return retVal;
    } // else ......
}

由 源码22 可知,注解声明式事务的核心是一个环绕通知。核心动作有4步:开启事务、执行Service方法、遇到异常时回滚事务、没有异常时提交事务

(1)成功的事务提交

执行完createTransactionIfNecessary方法后,事务成功开启。由于UserService的test方法正常执行,会触发下面的commitTransactionAfterReturning方法提交事务。

源码23TransactionAspectSupport.java

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

由 源码23 可知,提交事务的逻辑是获取到事务管理器后执行commit方法提交逻辑。

源码24AbstractPlatformTransactionManager.java

public final void commit(TransactionStatus status) throws TransactionException {
    // 如果事务已经完成,则无法提交,抛出异常
    if (status.isCompleted()) {
        // throw ......
    }
    // 如果事务已经被标记为需要回滚,则回滚事务
    DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
    if (defStatus.isLocalRollbackOnly()) {
        // logger ... 
        processRollback(defStatus, false);
        return;
    }
    // 如果事务已经标记为全局回滚,则进行回滚
    if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
        // logger ... 
        processRollback(defStatus, true);
        return;
    }
    // 正常情况下提交事务
    processCommit(defStatus);
}

由 源码24 可知,事务管理器的commit方法并不会直接提交事务,而是会先进行一些异常情况的检查,确保无误后再执行processCommit方法提交事务。

源码25AbstractPlatformTransactionManager.java

private void processCommit(DefaultTransactionStatus status) throws TransactionException {
    try {
        // ......

        if (status.hasSavepoint()) {
            // 存在事务保存点,处理保存点的逻辑
            unexpectedRollback = status.isGlobalRollbackOnly();
            status.releaseHeldSavepoint();
        } else if (status.isNewTransaction()) {
            // 新事务,直接提交
            unexpectedRollback = status.isGlobalRollbackOnly();
            doCommit(status);
        }
        
        // ......
    } catch ...
    } finally {
        cleanupAfterCompletion(status);
    }
}

由 源码24 可知,processCommit方法的核心动作是doCommit方法,该方法的实现在落地实现类DataSourceTransactionManager中。

源码26DataSourceTransactionManager.class

protected void doCommit(DefaultTransactionStatus status) {
    DataSourceTransactionManager.DataSourceTransactionObject txObject = (DataSourceTransactionManager.DataSourceTransactionObject) status.getTransaction();
    Connection con = txObject.getConnectionHolder().getConnection();
    // logger...
    }
    try {
        con.commit();
    } // catch ...
}

由 源码25 可知,doCommit方法会获取到原生JDBC的Connection,执行其commit方法完成事务提交。

(2)异常的事务回滚

执行完createTransactionIfNecessary方法后,事务成功开启。由于UserService的test方法的执行出现异常catch结构中的completeTransactionAfterThrowing方法回滚事务。

源码26TransactionAspectSupport.java

protected void completeTransactionAfterThrowing(@Nullable TransactionAspectSupport.TransactionInfo txInfo, Throwable ex) {
    if (txInfo != null && txInfo.getTransactionStatus() != null) {
        // logger ...
        // 如果当前异常在回滚范围之内,则会调用事务管理器回滚事务
        if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
            try {
                txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
            } // catch ......
        } else {
            // 如果不再回滚范围内,则依然会提交事务
            try {
                txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
            } // catch ......
        }
    }
}
源码27DefaultTransactionAttribute.java

public boolean rollbackOn(Throwable ex) {
    return (ex instanceof RuntimeException || ex instanceof Error);
}

由 源码26 可知,获取到异常后,completeTransactionAfterThrowing方法会根据异常类型决定是否回滚异常,如果当前异常在回滚范围之内,则会调用事务管理器的rollback方法回滚事务。

由 源码27 可知,默认情况下@Transactional注解控制回滚的异常类型包括Error和RuntimeException,对于普通的Exception默认不回滚。

这提示开发者在日常开发中,标注@Transactional时一定要通过设置其rollbackFor属性显式地声明事务回滚的异常类型。

源码28AbstractPlatformTransactionManager.java

public final void rollback(TransactionStatus status) throws TransactionException {
    // 如果事务已经完成,则无法继续回滚
	if (status.isCompleted()) {
		// throw ...
	}
    // 回滚事务
	DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
	processRollback(defStatus, false);
}

private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
    try {
        // 如果存在保存点,则直接回滚到保存点位置
        if (status.hasSavepoint()) {
            // logger ...
            status.rollbackToHeldSavepoint();
        } else if (status.isNewTransaction()) {
            // logger ...
            // 对于新事物,直接回滚
            doRollback(status);
        }
        // ......
    } catch ...
    } finally {
        cleanupAfterCompletion(status);
    }
}

由 源码28 可知,rollback方法的核心动作是doRollback方法,该方法的实现在落地实现类DataSourceTransactionManager中。

源码29DataSourceTransactionManager.java

protected void doRollback(DefaultTransactionStatus status) {
    DataSourceTransactionManager.DataSourceTransactionObject txObject = (DataSourceTransactionManager.DataSourceTransactionObject) status.getTransaction();
    Connection con = txObject.getConnectionHolder().getConnection();
    // logger ...
    try {
        con.rollback();
    } // catch ...
}

由 源码29 可知,doRollback方法会获取到原生JDBC的Connection,执行其rollback方法完成事务回滚。

10.4.2.5 事务执行的后处理

由 源码25、28 可知,无论是成功提交事务(processCommit方法)还是回滚事务(processRollback方法),最终都会执行一个cleanupAfterCompletion方法。

源码30AbstractPlatformTransactionManager.java

private void cleanupAfterCompletion(DefaultTransactionStatus status) {
    status.setCompleted();
    // 组件资源清除
    if (status.isNewSynchronization()) {
        TransactionSynchronizationManager.clear();
    }
    if (status.isNewTransaction()) {
        doCleanupAfterCompletion(status.getTransaction());
    }
    // 释放挂起的事务
    if (status.getSuspendedResources() != null) {
        // logger ...
        Object transaction = (status.hasTransaction() ? status.getTransaction() : null);
        resume(transaction, (AbstractPlatformTransactionManager.SuspendedResourcesHolder) status.getSuspendedResources());
    }
}

由 源码30 可知,cleanupAfterCompletion方法的前两个if结构与组件资源清除相关,最后一个if结构有一个resume方法,用于释放挂起的事务。

至此,整个事务控制全流程执行完毕。

······

本节完,更多内容请查阅分类专栏:SpringBoot源码解读与原理分析

  • 36
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

灰色孤星A

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值