找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

4981

积分

0

好友

679

主题
发表于 4 小时前 | 查看: 5| 回复: 0

前四篇我们完整打通了 Spring 核心底层链路:

容器启动 → Bean 生命周期全流程 → 循环依赖三级缓存 → AOP 代理生成与执行

而 Spring 声明式事务,本质就是 AOP 的一个典型业务落地实现:它基于动态代理,在目标方法执行前后,植入事务开启、提交、回滚的横向逻辑。

接下来,我们基于 Spring 源码,完整拆解声明式事务的全流程,一次性说清:

  1. @EnableTransactionManagement 到底做了什么?
  2. @Transactional 注解是怎么被解析的?事务代理如何生成?
  3. 运行时,事务的开启、提交、回滚完整执行链路是什么?
  4. 7 种事务传播行为,源码层面是如何实现的?
  5. 面试高频的「事务失效 9 大场景」,从源码层面说清为什么会失效?
  6. 事务与 AOP、循环依赖的关联关系是什么?

一、核心前提:Spring 事务的本质与核心组件

1. 事务的本质

Spring 声明式事务,完全基于 Spring AOP 动态代理实现

  • 容器启动时,扫描 @Transactional 注解,为目标 Bean 生成动态代理对象
  • 调用目标方法时,进入事务拦截器,在方法执行前开启事务,方法正常执行后提交事务,抛出异常时回滚事务
  • 整个逻辑完全复用 AOP 的代理生成、拦截器执行链路

2. 事务核心四大组件

组件 源码接口 / 类 核心作用
事务管理器 PlatformTransactionManager Spring 事务顶层接口,核心负责:事务开启、提交、回滚,最常用实现类 DataSourceTransactionManager
事务属性定义 TransactionDefinition 定义事务的规则:传播行为、隔离级别、超时时间、是否只读、回滚异常规则
事务状态 TransactionStatus 记录事务的运行状态:是否是新事务、是否已完成、是否有保存点、是否被标记为回滚
事务拦截器 TransactionInterceptor 事务 AOP 的核心通知类,继承自 MethodInterceptor,在目标方法执行前后植入事务逻辑

二、事务开启的入口:@EnableTransactionManagement

我们使用 Spring 声明式事务,第一步就是在配置类上加这个注解,它是整个事务逻辑的起点。

1. 注解源码拆解

@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;
}

2. 核心:TransactionManagementConfigurationSelector 做了什么?

这个选择器会根据 mode 属性,向 Spring 容器注册两个核心组件:

  1. AutoProxyRegistrar:注册事务的 AOP 代理创建器 InfrastructureAdvisorAutoProxyCreator,这是事务代理生成的核心,和 AOP 的 AnnotationAwareAspectJAutoProxyCreator 是同根同源的 BeanPostProcessor
  2. ProxyTransactionManagementConfiguration:注册事务的核心 Bean
    • 事务属性解析器 AnnotationTransactionAttributeSource:解析 @Transactional 注解的属性
    • 事务拦截器 TransactionInterceptor:事务核心逻辑的载体
    • 事务通知器 BeanFactoryTransactionAttributeSourceAdvisor:Spring AOP 的 Advisor,封装了切点 + 事务拦截器,是事务 AOP 的最小执行单元

关键源码佐证

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. 灵魂核心:InfrastructureAdvisorAutoProxyCreator

这个类是事务代理生成的核心,它的继承关系如下,本质就是一个 BeanPostProcessor:

InfrastructureAdvisorAutoProxyCreator
        ↓
AbstractAdvisorAutoProxyCreator
        ↓
AbstractAutoProxyCreator
        ↓
实现了 BeanPostProcessor 接口

它的核心作用

  • 它是一个 BeanPostProcessor,介入每一个 Bean 的生命周期
  • 容器启动时,会找到事务专用的 Advisor:BeanFactoryTransactionAttributeSourceAdvisor
  • Bean 创建时,在 postProcessAfterInitialization 后置处理中,判断 Bean 的方法是否有 @Transactional 注解,有则生成事务代理对象,替换原生 Bean

三、事务全流程第一阶段:容器启动时,事务代理生成

完整流程

容器refresh()
        ↓
1. invokeBeanFactoryPostProcessors:解析@EnableTransactionManagement,注册事务核心组件的BeanDefinition
        ↓
2. registerBeanPostProcessors:实例化InfrastructureAdvisorAutoProxyCreator,加入BeanPostProcessor列表
        ↓
3. finishBeanFactoryInitialization:实例化所有非懒加载单例Bean
        ↓
4. Bean初始化完成,进入postProcessAfterInitialization后置处理
        ↓
5. 匹配事务Advisor,判断方法是否有@Transactional注解
        ↓
6. 有事务注解 → 生成事务代理对象,替换原生Bean
        ↓
7. 代理对象放入单例池,对外提供服务

核心源码拆解

1. 事务注解解析:判断 Bean 是否需要生成代理

事务的切点匹配逻辑,在 BeanFactoryTransactionAttributeSourceAdvisor 中,核心是通过 AnnotationTransactionAttributeSource 解析类 / 方法上的 @Transactional 注解。

// 核心:解析@Transactional注解,获取事务属性
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
    // 【关键1】非public方法,直接返回null,不解析事务属性
    // 这就是非public方法事务失效的源码根源!
    if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
        return null;
    }
    // 优先找实现类方法上的@Transactional
    TransactionAttribute txAttr = findTransactionAttribute(method);
    if (txAttr != null) {
        return txAttr;
    }
    // 再找接口方法上的@Transactional
    txAttr = findTransactionAttribute(method.getDeclaringClass());
    if (txAttr != null && publicMethodOnlyForCreation) {
        return txAttr;
    }
    // 再找类上的@Transactional
    txAttr = findTransactionAttribute(targetClass);
    if (txAttr != null) {
        return txAttr;
    }
    // 没有@Transactional注解,返回null,不生成事务代理
    return null;
}

2. 事务代理生成入口:postProcessAfterInitialization

// AbstractAutoProxyCreator(事务和AOP共用的父类)
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        // 核心:判断是否需要生成事务代理,需要则返回代理对象
        return wrapIfNecessary(bean, beanName, cacheKey);
    }
    return bean;
}

关键细节

  • 事务代理和自定义 AOP 切面代理,是同一个逻辑生成的,共用 AbstractAutoProxyCreator 的代理生成能力
  • 如果一个 Bean 同时有自定义 AOP 切面和 @Transactional 注解,会生成同一个代理对象,通过 order 属性控制切面和事务拦截器的执行顺序
  • 循环依赖场景下,事务代理和 AOP 代理一样,会提前在 getEarlyBeanReference 中生成,保证循环依赖注入的是代理对象

四、事务全流程第二阶段:运行时核心

事务代理对象生成后,当我们调用加了 @Transactional 的方法时,会进入事务拦截器 TransactionInterceptor,执行完整的事务逻辑,这是声明式事务的核心。

核心执行总流程

调用@Transactional标注的方法
        ↓
进入事务代理对象的拦截器入口
        ↓
执行TransactionInterceptor.invoke()
        ↓
进入invokeWithinTransaction()【事务核心逻辑全在这里】
        ↓
1. 解析@Transactional注解的事务属性
        ↓
2. 获取事务管理器PlatformTransactionManager
        ↓
3. 根据传播行为,开启事务(创建/挂起事务)
        ↓
4. 执行目标方法
        ↓
5. 异常:判断是否需要回滚,执行回滚/提交
        ↓
6. 正常执行:提交事务,恢复被挂起的事务

核心源码拆解:事务执行的灵魂方法 invokeWithinTransaction

protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
                                         final InvocationCallback invocation) throws Throwable {
    // 1. 解析 @Transactional 事务属性
    TransactionAttributeSource tas = getTransactionAttributeSource();
    final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
    // 2. 获取事务管理器
    final PlatformTransactionManager tm = determineTransactionManager(txAttr);
    PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
    // 3. 方法标识
    final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
    // ==============================================================
    // 优先判断回调式事务(JTA/WebLogic)
    // ==============================================================
    if (txAttr != null && ptm instanceof CallbackPreferringPlatformTransactionManager) {
        ThrowableHolder throwableHolder = new ThrowableHolder();
        Object result;
        try {
            result = ((CallbackPreferringPlatformTransactionManager) ptm).execute(txAttr, status -> {
                TransactionInfo txInfo = prepareTransactionInfo(ptm, txAttr, joinpointIdentification, status);
                try {
                    return invocation.proceedWithInvocation();
                } catch (Throwable ex) {
                    if (txAttr.rollbackOn(ex)) {
                        throw ex;
                    } else {
                        throwableHolder.throwable = ex;
                        return null;
                    }
                } finally {
                    cleanupTransactionInfo(txInfo);
                }
            });
        } catch (ThrowableHolderException ex) {
            throw ex.getCause();
        }
        return result;
    }
    // ==============================================================
    // 【★ 99.9% 项目走这里 ★】标准本地事务
    // ==============================================================
    else {
        // 1. 根据传播行为开启事务
        TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
        Object retVal;
        try {
            // 2. 执行业务方法
            retVal = invocation.proceedWithInvocation();
        } catch (Throwable ex) {
            // 3. 异常回滚
            completeTransactionAfterThrowing(txInfo, ex);
            throw ex;
        } finally {
            cleanupTransactionInfo(txInfo);
        }
        // 4. 正常提交
        commitTransactionAfterReturning(txInfo);
        return retVal;
    }
}

异常回滚:completeTransactionAfterThrowing

protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
    if (txInfo != null && txInfo.getTransactionStatus() != null) {
        // 【关键】判断异常是否符合回滚规则
        // 默认:只有RuntimeException和Error才会回滚,受检异常不会回滚
        if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
            try {
                // 执行回滚
                txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
            }
            catch (TransactionSystemException ex2) {
                throw ex2;
            }
        }
        else {
            // 不符合回滚规则,依然提交事务
            try {
                txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
            }
            catch (TransactionSystemException ex2) {
                throw ex2;
            }
        }
    }
}

事务提交:commitTransactionAfterReturning

protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
    if (txInfo != null && txInfo.getTransactionStatus() != null) {
        // 执行事务提交
        txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
    }
}

五、面试核心考点:7 种事务传播行为

事务传播行为,是 Spring 事务最核心、最高频的面试考点,它定义了:当一个带事务的方法,被另一个带事务的方法调用时,事务该如何处理

所有传播行为定义在 TransactionDefinition 接口中,核心 7 种,我们按源码实现逻辑分为 3 大类:

传播行为 常量名 核心行为
必需(默认) PROPAGATION_REQUIRED 有事务就加入,没有就新建事务
支持 PROPAGATION_SUPPORTS 有事务就加入,没有就以非事务运行
强制 PROPAGATION_MANDATORY 必须在已有事务中运行,没有就抛异常
必需新建 PROPAGATION_REQUIRES_NEW 无论有没有事务,都新建一个独立事务,挂起当前事务
不支持 PROPAGATION_NOT_SUPPORTED 以非事务运行,挂起当前事务
从不 PROPAGATION_NEVER 必须非事务运行,有事务就抛异常
嵌套 PROPAGATION_NESTED 已有事务则创建嵌套事务(保存点),没有则新建事务

高频传播行为源码实现拆解

1. 默认传播行为:PROPAGATION_REQUIRED

// AbstractPlatformTransactionManager.getTransaction() 核心分支
if (isExistingTransaction(transaction)) {
    // 已有事务 → 加入当前事务
    return handleExistingTransaction(def, transaction, debugEnabled);
}
// 没有事务 → 新建事务
return startTransaction(def, transaction, debugEnabled, suspendedResources);

核心特点

  • 内外方法共用同一个事务,任何一个方法触发回滚,整个事务全部回滚
  • 最常用,Spring 默认选择

2. 独立事务:PROPAGATION_REQUIRES_NEW

// handleExistingTransaction 核心分支
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
    // 1. 挂起当前事务
    SuspendedResourcesHolder suspendedResources = suspend(transaction);
    try {
        // 2. 新建一个完全独立的新事务
        return startTransaction(definition, transaction, debugEnabled, suspendedResources);
    }
    catch (RuntimeException | Error ex) {
        // 新事务异常,恢复被挂起的旧事务
        resume(transaction, suspendedResources);
        throw ex;
    }
}

核心特点

  • 内外方法是两个完全独立的事务,内方法事务提交 / 回滚,不影响外方法
  • 外方法异常回滚,不会影响已经提交的内方法事务

3. 嵌套事务:PROPAGATION_NESTED

// handleExistingTransaction 核心分支
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
    // 1. 校验是否支持嵌套事务
    if (!isNestedTransactionAllowed()) {
        throw new NestedTransactionNotSupportedException(...);
    }
    // 2. 创建保存点,嵌套事务回滚只回滚到保存点,不影响主事务
    DefaultTransactionStatus status = newTransactionStatus(
            definition, transaction, false, debugEnabled, suspendedResources);
    status.createAndHoldSavepoint();
    return status;
}

核心特点

  • 基于 JDBC 的保存点 Savepoint 实现,嵌套事务是主事务的子事务
  • 内方法异常回滚,只会回滚到保存点,主事务可以继续执行、提交
  • 主事务异常回滚,整个嵌套事务全部回滚

六、事务失效 9 大场景

失效场景 源码级失效原因
1. 非 public 方法标注 @Transactional 源码中 computeTransactionAttribute 方法,非 public 方法直接返回 null,不解析事务属性,不会生成代理,事务失效
2. 类内部方法调用(this 调用) 内部调用使用的是 this 原生对象,不是事务代理对象,不会进入事务拦截器,事务逻辑无法执行
3. 异常被 try-catch 捕获,没有抛出 事务回滚的触发点是拦截器捕获到目标方法抛出的异常,异常被捕获后,拦截器感知不到异常,不会执行回滚
4. 抛出非 RuntimeException/Error 异常 默认回滚规则 rollbackOn 方法,只对 RuntimeException 和 Error 回滚,受检异常(如 IOException)不会触发回滚,除非手动指定 rollbackFor = Exception.class
5. 传播行为配置错误 比如使用 NOT_SUPPORTED/NEVER 传播行为,会以非事务运行;SUPPORTS 在无事务环境下,也不会开启事务
6. 标注 @Transactional 的类没有被 Spring 管理 没有加 @Service/@Component 注解,Bean 没有被 Spring 容器管理,无法生成事务代理对象,事务失效
7. 多线程场景下调用事务方法 Spring 事务是基于线程绑定的 ThreadLocal 实现的,多线程场景下,线程拿到的不是同一个数据库连接,事务无法生效
8. 数据源没有配置事务管理器 没有向容器注册 PlatformTransactionManager,Spring 无法开启、提交、回滚事务,即使加了注解也无效
9. 方法被 final/static 修饰 final 方法无法被 CGLIB 代理重写,static 方法属于类,无法被代理,无法进入事务拦截器,事务失效

七、事务完整链路精简版

1. @EnableTransactionManagement 开启事务,注册事务核心组件
        ↓
2. 容器启动,扫描@Transactional注解,生成事务Advisor
        ↓
3. Bean创建时,后置处理匹配事务注解,生成代理对象
        ↓
4. 代理对象替换原生Bean,放入单例池
        ↓
5. 调用事务方法,进入TransactionInterceptor事务拦截器
        ↓
6. 解析事务属性,获取事务管理器,根据传播行为开启事务
        ↓
7. 执行目标方法
        ↓
8. 异常:匹配回滚规则,执行回滚/提交
        ↓
9. 正常:提交事务,恢复被挂起的事务

debug时核心断点位置

断点类全称 断点方法 调试内容
TransactionInterceptor invokeWithinTransaction() 事务执行全流程核心入口
AnnotationTransactionAttributeSource computeTransactionAttribute() 事务注解解析,验证非 public 方法失效
AbstractPlatformTransactionManager getTransaction() 事务开启、传播行为处理
TransactionInterceptor completeTransactionAfterThrowing() 异常回滚逻辑
TransactionInterceptor commitTransactionAfterReturning() 事务提交逻辑

八、面试高频问题

1. Spring 事务的底层实现原理是什么?

答:Spring 声明式事务基于 Spring AOP 动态代理实现,核心分为两个阶段:

  • 容器启动阶段:扫描 @Transactional 注解,为目标 Bean 生成动态代理对象,将事务拦截器 TransactionInterceptor 织入代理对象中。
  • 运行时阶段:调用事务方法时,进入事务拦截器,根据事务属性,通过事务管理器在方法执行前开启事务,方法正常执行后提交事务,抛出异常时根据回滚规则执行回滚。

2. @Transactional 注解在什么情况下会失效?

答:见本文第六部分的 9 大失效场景,核心原因分为 4 类:

  • 代理不生效:非 public 方法、内部调用、类没被 Spring 管理、final/static 方法
  • 异常处理不当:异常被捕获、抛出非回滚异常
  • 配置错误:传播行为配置错误、没有配置事务管理器
  • 特殊场景:多线程调用、数据源不支持事务

3. Spring 事务的传播行为有哪些?核心区别是什么?

答:Spring 有 7 种事务传播行为,核心分为 3 类:

  • 加入当前事务:REQUIRED、SUPPORTS、MANDATORY
  • 独立事务:REQUIRES_NEW、NOT_SUPPORTED、NEVER
  • 嵌套事务:NESTED

核心区别是:REQUIRED 共用事务,一个回滚全回滚;REQUIRES_NEW 是独立事务,互不影响;NESTED 是嵌套事务,子事务回滚不影响主事务,主事务回滚子事务全回滚。

4. Spring 事务的隔离级别有哪些?和数据库隔离级别的关系?

答:Spring 定义了 5 种隔离级别,对应数据库的 4 种标准隔离级别:

  • DEFAULT:使用数据库默认的隔离级别(MySQL 默认 REPEATABLE READ)
  • READ_UNCOMMITTED:读未提交
  • READ_COMMITTED:读已提交
  • REPEATABLE_READ:可重复读
  • SERIALIZABLE:串行化

Spring 的隔离级别最终会传递给数据库连接,由数据库实现隔离级别,Spring 本身不实现隔离逻辑。

5. 事务和 AOP 的关系是什么?

答:Spring 声明式事务是 AOP 的一个典型业务实现,完全复用 AOP 的核心能力:

  • 基于 BeanPostProcessor 生成动态代理对象
  • 基于 MethodInterceptor 实现事务逻辑的植入
  • 基于 Advisor 封装事务的切点和通知
  • 事务拦截器的执行,完全遵循 AOP 的通知链责任链模式

下篇预告

第六篇我们进入 Spring Web 核心考点:Spring MVC 全流程源码深度拆解

  • @EnableWebMvc到底做了什么?
  • Spring MVC 请求处理全流程,从浏览器发请求到响应返回
  • 九大组件的核心作用:HandlerMapping、HandlerAdapter、ViewResolver 等
  • @Controller/@RequestMapping注解是如何被解析的?
  • 参数绑定、返回值处理的底层实现

希望这篇对 Spring 事务源码解析的深度拆解能帮助你彻底理解其底层原理。如果你想系统性地学习更多JavaSpring的核心技术,欢迎来云栈社区与更多开发者一起交流成长。




上一篇:x86汇编实战:手把手实现学生管理系统CRUD功能
下一篇:AI时代文档范式转移:DeepWiki、Code Wiki等工具如何让机器成为主要读者
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-4-23 06:22 , Processed in 2.048271 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表