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 篇,由浅入深持续更新中。有疑问或想深挖的源码点,评论区告诉我,下篇见。

相关推荐
智慧物业老杨2 小时前
物业数字化落地思考:真正的转型,是底层数据秩序的重构
java·大数据·人工智能·微服务·系统架构
星空5 小时前
金蝶苍穹build.gradle配置
java·build.gradle
两点王爷6 小时前
PostgreSQL 常用 SQL 语句与 GIS 相关函数详解
数据库·后端
两点王爷6 小时前
PostgreSQL 好用又独特的特性与空间函数
数据库
梦帮科技6 小时前
AI 音乐产品的发布工程:验证门、数据发布、回滚与生产运维纪律
数据结构·数据库·架构·node.js·音视频·动态规划·推荐算法
考虑考虑6 小时前
Springboot环境变量占位符语法
spring boot·后端·spring
TDengine (老段)7 小时前
TDengine 常见问题 TOP3
大数据·数据库·物联网·时序数据库·tdengine·涛思数据
步行cgn8 小时前
Spring 基于 XML 的自动装配:byName 详解
java·后端·spring
不会c+8 小时前
Day02 - 需求分析与用例建模
spring
大帅点兵8 小时前
Apache Ant 1.9.9 完整讲解
java