Spring @Transactional 代理机制与运行时事务拦截原理详解

阿静酱_1545

阿静酱_1545

2026-07-31

597人浏览

原创

Spring @Transactional 代理机制与运行时事务拦截原理详解

本文深入解析 Spring 如何通过动态代理与 TransactionInterceptor 实现声明式事务,阐明代理对象不生成真实字节码、而是基于 InvocationHandler(如 JdkDynamicAopProxy)在运行时织入事务逻辑,并重点说明事务上下文如何借助 ThreadLocal 隔离多线程场景下的 EntityManager 并发访问问题。

本文深入解析 spring 如何通过动态代理与 `transactioninterceptor` 实现声明式事务,阐明代理对象不生成真实字节码、而是基于 `invocationhandler`(如 `jdkdynamicaopproxy`)在运行时织入事务逻辑,并重点说明事务上下文如何借助 `threadlocal` 隔离多线程场景下的 `entitymanager` 并发访问问题。

Spring 的 @Transactional 注解从不生成可查看的“代理类源码”(如 .java 文件),它也不像编译期 AOP(如 AspectJ)那样生成新类字节码。所谓“代理”,本质是运行时动态构建的轻量级包装对象:对实现接口的 Bean,Spring 使用 JDK 动态代理(基于 java.lang.reflect.Proxy 和 InvocationHandler);对无接口的类,则采用 CGLIB 字节码增强(生成目标类的子类)。二者均不落地为物理文件,因此无法直接“查看代理代码”,但可通过调试或反编译观察其行为。

真正的事务逻辑入口是 TransactionInterceptor.invoke() 方法。该拦截器实现了 MethodInterceptor 接口,被植入代理对象的调用链中。当外部调用标注 @Transactional 的方法时,实际执行流程如下:

// 简化版 TransactionInterceptor.invoke 核心逻辑示意
public Object invoke(MethodInvocation invocation) throws Throwable {
    Method method = invocation.getMethod();
    Class> targetClass = AopUtils.getTargetClass(invocation.getThis());

    // 1. 解析事务属性(来自 @Transactional 注解)
    TransactionAttribute txAttr = transactionAttributeSource.getTransactionAttribute(method, targetClass);

    // 2. 获取事务管理器(如 DataSourceTransactionManager)
    PlatformTransactionManager ptm = determineTransactionManager(txAttr);

    // 3. 开启/加入事务(关键:prepareTransactionInfo 创建 ThreadLocal 绑定)
    TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, methodIdentification);

    Object result;
    try {
        // 4. 执行原始业务方法
        result = invocation.proceed();
    } catch (Throwable ex) {
        // 5. 异常时按规则回滚(txAttr.rollbackOn(ex) 判定)
        completeTransactionAfterThrowing(txInfo, ex);
        throw ex;
    } finally {
        // 6. 正常完成则提交,或清理事务资源
        cleanupTransactionInfo(txInfo);
    }

    // 7. 提交事务(若未异常且满足提交条件)
    commitTransactionAfterReturning(txInfo);
    return result;
}

值得注意的是:Spring 绝不会 在业务方法中直接插入类似 em.getTransaction().begin() 这样的硬编码。相反,它通过 PlatformTransactionManager(如 DataSourceTransactionManager)统一管控事务生命周期。该管理器内部维护一个 ThreadLocal 映射,确保每个线程拥有独立的事务状态——这正是解决多线程并发安全的核心机制:

Cici
Cici

一款AI翻译工具,主要用于Cici 是你的AI聊天助手,可以用于智能对话、写作、翻译、情感支持和编程,是您寻求建议、解答和聊天的首选伙伴,适合需要提升相关任务效率的用户。

下载
  • 当线程 A 调用 @Transactional 方法 → DataSourceTransactionManager.doBegin() 获取连接并绑定到当前线程的 ThreadLocal;
  • 线程 B 同时调用同一方法 → 独立获取另一连接,同样绑定至自身 ThreadLocal;
  • EntityManager(或 JdbcTemplate)底层通过 TransactionSynchronizationManager 获取当前线程关联的连接,从而天然避免“重复 begin”异常。

✅ 关键结论与注意事项:

  • 代理不可见,但行为可追踪:启用 JVM 参数 -Dsun.misc.ProxyGenerator.saveGeneratedFiles=true 可导出 JDK 代理的 .class 文件(仅限 JDK 代理,且需调试支持);CGLIB 代理类名形如 OrderService$$EnhancerBySpringCGLIB$$a1b2c3d4,可通过 System.out.println(bean.getClass()) 查看。
  • 事务失效常见陷阱:同一类内方法自调用(this.methodB())绕过代理,导致 @Transactional 不生效;务必通过 Spring 容器注入本类实例或使用 AopContext.currentProxy()。
  • EntityManager 线程安全前提:@PersistenceContext 注入的 EntityManager 是容器托管的 代理对象(非原生 JPA EntityManager),其所有操作(persist, find, getTransaction())均被 TransactionSynchronizationManager 拦截并路由至当前线程绑定的事务资源,故无需也不应手动调用 getTransaction().begin() —— 这会破坏 Spring 的事务上下文隔离。

综上,Spring 的事务魔法不在“生成代码”,而在“运行时编织”与“线程级上下文隔离”。理解 TransactionInterceptor 的拦截链、PlatformTransactionManager 的资源绑定机制,以及 ThreadLocal 在事务传播中的枢纽作用,才是掌握声明式事务本质的关键。

相关专题

更多
spring框架介绍
spring框架介绍

本专题整合了spring框架相关内容,想了解更多详细内容,请阅读专题下面的文章。

2025.08.06

2091

22

Java Spring Security 与认证授权
Java Spring Security 与认证授权

本专题系统讲解 Java Spring Security 框架在认证与授权中的应用,涵盖用户身份验证、权限控制、JWT与OAuth2实现、跨站请求伪造(CSRF)防护、会话管理与安全漏洞防范。通过实际项目案例,帮助学习者掌握如何 使用 Spring Security 实现高安全性认证与授权机制,提升 Web 应用的安全性与用户数据保护。

2026.01.26

377

25

spring框架介绍
spring框架介绍

本专题整合了spring框架相关内容,想了解更多详细内容,请阅读专题下面的文章。

2025.08.06

2091

22

Java Spring Security 与认证授权
Java Spring Security 与认证授权

本专题系统讲解 Java Spring Security 框架在认证与授权中的应用,涵盖用户身份验证、权限控制、JWT与OAuth2实现、跨站请求伪造(CSRF)防护、会话管理与安全漏洞防范。通过实际项目案例,帮助学习者掌握如何 使用 Spring Security 实现高安全性认证与授权机制,提升 Web 应用的安全性与用户数据保护。

2026.01.26

377

25

Vibeknow在线使用入口合集
Vibeknow在线使用入口合集

本专题汇总了Vibeknow在线创作视频的官方入口及网页版使用教程,涵盖PPT、PDF、Word等文档一键转讲解视频的核心操作,并整理了免费版水印规则与手机端浏览器访问指南,助你快速将知识内容视频化。

2026.09.21

0

20

NumPy随机数文件读写与dtype数据类型
NumPy随机数文件读写与dtype数据类型

本专题整理 NumPy 随机数、文件读写与 dtype 数据类型相关教程,覆盖 Generator/random、随机数种子、正态分布采样、npy/npz/CSV/TXT 保存读取、loadtxt/savetxt、memmap、大文件处理、astype 类型转换、结构化 dtype、整数溢出和精度丢失等场景。

2026.09.21

0

24

NumPy矩阵运算与线性代数计算
NumPy矩阵运算与线性代数计算

本专题整理 NumPy 矩阵运算与线性代数计算相关教程,覆盖矩阵乘法、dot 与 @ 运算符、逆矩阵、行列式、特征值与特征向量、SVD、线性方程组、欧氏距离、矩阵分解和大规模矩阵性能优化等内容,帮助读者掌握 np.linalg 与矩阵计算实战。

2026.09.21

0

20

NumPy广播机制数学运算与统计分析
NumPy广播机制数学运算与统计分析

本专题整理 NumPy 广播机制、数组数学运算与统计分析相关教程,覆盖广播规则、维度对齐、矩阵与数组加减除法、向量化计算、均值方差、分位数、中位数、直方图和 unique 频次统计等场景,帮助读者掌握 ndarray 高效计算与统计处理方法。

2026.09.21

0

17

NumPy数组创建索引切片与数据选择
NumPy数组创建索引切片与数据选择

本专题整理 NumPy 数组创建、索引、切片与数据选择相关教程,覆盖 np.array、zeros/ones、多维数组形状、基础切片、花式索引、布尔索引、条件筛选、视图与副本等常用场景,帮助读者系统掌握 ndarray 数据构造与高效提取方法。

2026.09.21

0

12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.6万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.1万人学习