Spring 源码系列(25): @EnableTransactionManagement 与 TransactionInterceptor

📌 阅读前提示 :进入 声明式事务阶段(第 25--27 篇) 。事务是 Spring 最实用的能力之一,底层却是纯 AOP (呼应第 11--14 篇)。本篇讲开关 @EnableTransactionManagement 和真正干活的拦截器 TransactionInterceptor------@Transactional 为什么能「自动开事务、提交、回滚」。


一、引子:@Transactional 背后是 AOP

你已经知道 AOP 能在方法前后织入逻辑。@Transactional 正是用一个环绕通知 (AOP 的 @Around 等价物)包住你的方法:进入前「开启事务」,正常返回「提交」,抛异常「回滚」。

这个环绕通知就是 TransactionInterceptor


二、@EnableTransactionManagement 注册了什么

java 复制代码
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
    boolean proxyTargetClass() default false;   // 代理方式
    AdviceMode mode() default AdviceMode.PROXY;  // PROXY 或 ASPECTJ
}

TransactionManagementConfigurationSelector 导入两个关键配置:

java 复制代码
// ① ProxyTransactionManagementConfiguration(核心)
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
    // ★ 事务拦截器(环绕通知)
    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public TransactionInterceptor transactionInterceptor(TransactionAttributeSource tas) {
        TransactionInterceptor interceptor = new TransactionInterceptor();
        interceptor.setTransactionAttributeSource(tas);
        // transactionManager 也会被注入
        return interceptor;
    }
    // ★ 把拦截器包装成 Advisor(BeanFactoryTransactionAttributeSourceAdvisor)
    @Bean
    public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(...) {
        BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
        advisor.setTransactionAttributeSource(tas);
        advisor.setAdvice(transactionInterceptor);   // ← 拦截器作为通知
        return advisor;
    }
}

📌 关键点 :这和 AOP 阶段完全一致------TransactionInterceptor(通知)被包进 Advisor,由 AbstractAutoProxyCreatorwrapIfNecessary 时匹配到 @Transactional 方法并生成代理(第 13 篇)。事务 = 一个特殊的 AOP Advisor


三、TransactionInterceptor:事务环绕通知

java 复制代码
// TransactionInterceptor.java
@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
    // ① 解析事务属性(@Transactional 的 propagation/isolation/timeout 等)
    TransactionAttribute txAttr = determineTransactionAttribute(invocation.getMethod());
    // ② 取出事务管理器
    PlatformTransactionManager tm = determineTransactionManager(txAttr);
    // ③ 执行:开事务 → 调目标方法 → 提交/回滚
    return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}

3.1 invokeWithinTransaction 三段式

java 复制代码
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, InvocationCallback invocation) {
    // 1. 创建事务(按传播行为决定新建/加入已有)
    TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
    Object retVal;
    try {
        retVal = invocation.proceed();        // ★ 调用你的业务方法
    } catch (Throwable ex) {
        // 2. 异常 → 按 rollbackOn 规则决定回滚
        completeTransactionAfterThrowing(txInfo, ex);
        throw ex;
    } finally {
        cleanupTransactionInfo(txInfo);
    }
    // 3. 正常返回 → 提交
    commitTransactionAfterReturning(txInfo);
    return retVal;
}

💡 重点 :事务的「提交/回滚」决策在 completeTransactionAfterThrowing------默认只有 RuntimeException / Error 回滚,checked Exception 不回滚(可用 @Transactional(rollbackFor=...) 改)。


四、事务拦截器在 AOP 链中的位置


五、常见误区

误区 正解
@Transactional 是独立机制 不,它是 AOP + TransactionInterceptor 包装而成
所有异常都回滚 RuntimeException/Error 默认回滚,checked 不回滚
事务由 @EnableTransactionManagement 直接执行 不,它只注册 Advisor,真正执行靠 TransactionInterceptor
没有事务管理器也能用 PlatformTransactionManager Bean,Boot 自动配好
@Transactional 加在 private 方法生效 不,AOP 代理无法拦截 private(类似自调用失效,第14篇)

🧪 面试题自测

  1. @EnableTransactionManagement 注册了哪两个核心 Bean?
  2. TransactionInterceptor 在 AOP 体系里扮演什么角色?
  3. 事务的「提交/回滚」在哪一步决策?
  4. 为什么 checked Exception 默认不回滚?
  5. 事务为什么是环绕通知而不是前置/后置?
  6. 事务管理器和 TransactionInterceptor 的关系?

🔧 Debug 小技巧

TransactionInterceptor.invokeWithinTransaction 断点,观察 txInfo 如何创建、事务状态对象里的 newTransaction 标记;再在 completeTransactionAfterThrowing 断点,故意抛异常,看 txInfo.transactionAttribute.rollbackOn(ex) 如何判定回滚。


下一篇预告

第 26 篇:事务传播行为源码------PROPAGATION_REQUIRED / REQUIRES_NEW / NESTED 等 7 种行为,在 AbstractPlatformTransactionManager.getTransaction 里到底如何决策「新建还是加入」。


如果这篇对你有帮助,欢迎 点赞 · 收藏 · 关注 三连支持。

Spring 源码系列共 30 篇,由浅入深持续更新中。有疑问或想深挖的源码点,评论区告诉我,下篇见。

相关推荐
l1t24 分钟前
DeepSeek总结的DuckDB访谈:DuckDB的崛起、扩展与AWS收购
数据库·云计算·aws·duckdb
隔窗听雨眠34 分钟前
CI/CD测试数据清理完全指南:从污染根因到三层清理覆盖的完整方案
java·数据库·ci/cd
MetaLite34 分钟前
Spring-Scheduled多实例重复执行怎么办-Redis分布式锁如何只让一个节点运行
redis·分布式·spring
Query*39 分钟前
Agent 开发之项目 AI 能力自我进化:通过浏览器自动化与数据采集实现持续学习
java·人工智能·ai·自动化
无定义_42 分钟前
Bellman-Ford——贝尔曼福特算法
数据库·算法
盟接之桥1 小时前
半导体供应链破局:EDI如何成为中国制造的数字通行证
大数据·运维·服务器·网络·数据库·人工智能·制造
晓晓_za8986681 小时前
GEO 搜索源码白帽合规改造:适配各大 AI 信源收录规则
java·开发语言·人工智能·性能优化·开源
Haooog1 小时前
从 Tool Calling 到 State 并发控制:一个 Agent 如何安全地连续执行任务
java·agent·后端开发
其实防守也摸鱼1 小时前
ZLibrary 类项目合规避坑指南:从技术实现到法律风险的全景梳理
运维·服务器·数据库·安全·自动化·github·copilot