Spring 源码探险:事务管理的终极奥义——@Transactional 背后的深水区
@Transactional
,它可能是我们代码库中最常见、也最能给我们带来“安全感”的注解。我们把它标注在 Service 方法上,就仿佛给这段代码上了一道保险。我们坚信,方法内的所有数据库操作,都会被一个原子性的事务包裹。
但这种“信念”,往往是盲目的。
你是否想过:
- Spring 是如何知道一个方法需要事务的?仅仅因为一个注解吗?
- 事务是在方法执行的哪个瞬间开启的?又是在哪个瞬间提交或回滚的?
Connection
对象是如何在不同 DAO 方法之间传递并保持统一的?- 当
RuntimeException
抛出时,回滚是如何被触发的?那Exception
呢? @Transactional
的propagation
(传播行为)和isolation
(隔离级别)这些属性,又是如何影响底层代码执行的?
@Transactional
对我们来说,就像一个最熟悉的陌生人。我们每天与它擦肩而过,却从未真正了解过它的内心。今天,我们的终极任务,就是彻底撬开它的心防,看清它背后那套由 IoC、AOP 和数据库连接共同编织的、复杂而精密的控制逻辑。
第一章:@Transactional
的黎明——它何时生效?
首先要明确一个核心前提:@Transactional
注解本身,不具备任何能力。 它和 @Override
一样,是一个纯粹的元数据“标记”。让这个标记“活”起来的,是我们早已探明的老朋友——Spring AOP。
在现代 Spring Boot 应用中,这一切是如何自动发生的?
- 自动配置的起点:
TransactionAutoConfiguration
- 在 Spring Boot 的“藏宝图” (
AutoConfiguration.imports
) 中,赫然列着TransactionAutoConfiguration
。 - 这个自动配置类被
@ConditionalOnClass({ PlatformTransactionManager.class })
守护着。当我们引入spring-boot-starter-jdbc
或spring-boot-starter-data-jpa
时,DataSourceTransactionManagerAutoConfiguration
会被激活,它会为我们自动配置一个DataSourceTransactionManager
的 Bean(它就是PlatformTransactionManager
的一种实现)。 - 这个条件一旦满足,
TransactionAutoConfiguration
就会生效。 - 开启事务管理:
@EnableTransactionManagement
TransactionAutoConfiguration
的主要作用,就是替我们加上了那个在非 Boot 时代需要手动添加的核心注解:@EnableTransactionManagement
。- 导入核心组件:
ProxyTransactionManagementConfiguration
@EnableTransactionManagement
会通过@Import
导入一个名为ProxyTransactionManagementConfiguration
的配置类。- 这个配置类,是整个事务 AOP 功能的“兵工厂”。它向 Spring IoC 容器中注册了几个至关重要的 Bean。其中最重要的一个,就是事务
Advisor
。 - 源码路径:
org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration
@Configuration(proxyBeanMethods = false)
public class ProxyTransactionManagementConfiguration {
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
TransactionAttributeSource transactionAttributeSource,
TransactionInterceptor transactionInterceptor) {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource);
advisor.setAdvice(transactionInterceptor);
// ...
return advisor;
}
// ... 还注册了 TransactionAttributeSource 和 TransactionInterceptor
}
看,最终的秘密武器登场了!它是一个 Advisor
!结合我们对 AOP 的理解,一切都说得通了:
- Spring Boot 自动配置了事务
Advisor
。 - 这个
Advisor
会在 Bean 初始化时,像所有其他Advisor
一样,通过Pointcut
去匹配所有方法。 - 一旦某个方法被
@Transactional
标注,Pointcut
匹配成功,AOP 就会为这个 Bean 创建一个代理对象。
至此,所有被 @Transactional
标注的方法,都已经处在 AOP 代理的掌控之下了。
第二章:TransactionInterceptor
——事务 AOP 的心脏
BeanFactoryTransactionAttributeSourceAdvisor
这个 Advisor
的结构非常经典:
- Pointcut (切点): 它内部的
TransactionAttributeSourcePointcut
负责匹配。它会扫描方法,如果方法上或方法所在的类上存在@Transactional
注解,则匹配成功。 - Advice (通知): 这就是
ProxyTransactionManagementConfiguration
中注册的另一个核心 Bean——TransactionInterceptor
。它是一个MethodInterceptor
,是真正执行事务逻辑的地方。
当我们调用一个被代理的、带有 @Transactional
注解的方法时,AOP 的调用链机制会启动,最终会执行到 TransactionInterceptor
的 invoke
方法。
- 源码路径:
org.springframework.transaction.interceptor.TransactionInterceptor#invoke
这个 invoke
方法,就是我们本次探险的“风暴中心”。所有关于事务的开启、提交、回滚、传播行为的复杂逻辑,都封装于此。
第三章:invoke
方法内的风暴——事务的完整生命周期
TransactionInterceptor
的 invoke
方法,将核心逻辑委托给了父类 TransactionAspectSupport
的一个同名方法。让我们直接进入这个核心。
- 源码路径:
org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction
// TransactionAspectSupport.java
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
// 1. 获取事务属性 (@Transactional注解中的 propagation, isolation, timeout 等信息)
TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
// 2. 获取 PlatformTransactionManager (例如 DataSourceTransactionManager)
PlatformTransactionManager ptm = determineTransactionManager(txAttr);
// ...
// 3. 开启事务 (最核心的步骤)
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// 4. 执行真正的目标方法 (AOP调用链的 proceed())
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// 5. 如果发生异常,执行回滚
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
// 6. 清理事务信息
cleanupTransactionInfo(txInfo);
}
// 7. 如果没有异常,执行提交
commitTransactionAfterReturning(txInfo);
return retVal;
}
这段代码就是 @Transactional
的完整生命周期。让我们把它拆解成一部“七步史诗”:
getTransactionAttribute()
- 获取事务属性:它会解析方法上的
@Transactional
注解,将其所有属性(propagation
、isolation
、timeout
、readOnly
、rollbackFor
等)封装成一个TransactionAttribute
对象。这是后续所有决策的依据。determineTransactionManager()
- 寻找事务管理器:找到容器中配置的
PlatformTransactionManager
Bean。createTransactionIfNecessary()
- 创建事务(如果需要):这是风暴的真正核心!
它内部的逻辑会根据
@Transactional
的
传播行为 (
propagation
)做出不同决策:
PROPAGATION_REQUIRED
(默认):- 检查当前线程是否已经存在一个事务。
- 如果不存在,就调用
ptm.getTransaction(txAttr)
开启一个新的物理事务。这通常意味着执行connection.setAutoCommit(false)
。 - 如果存在,就加入到当前事务中,什么都不做,继续执行。
PROPAGATION_REQUIRES_NEW
:- 不管当前是否存在事务,总是调用
ptm.getTransaction(txAttr)
开启一个全新的物理事务。如果当前已有事务,会先将它“挂起”。 PROPAGATION_NESTED
:- 如果当前存在事务,则创建一个“嵌套事务”(利用数据库的
Savepoint
机制)。如果不存在,则行为同REQUIRED
。 - 其他传播行为以此类推…
最终,它会返回一个
TransactionInfo
对象,其中包含了事务状态 (TransactionStatus
) 和事务管理器等信息。invocation.proceedWithInvocation()
- 执行目标方法:调用 AOP 调用链的
proceed()
方法,最终执行到我们 Service 中的业务逻辑代码,包括所有的 DAO 操作。关键点: 由于事务已经开启,此时从
DataSource
获取的Connection
都是同一个(通过TransactionSynchronizationManager
绑定到当前线程),从而保证了所有数据库操作在同一个事务中。completeTransactionAfterThrowing()
- 异常时回滚:如果
proceed()
抛出了异常,此方法会被调用。它会检查异常类型是否匹配
@Transactional
注解中rollbackFor
或noRollbackFor
的规则。(默认只对RuntimeException
和Error
回滚)。如果判断需要回滚,则会调用
ptm.rollback(txInfo.getTransactionStatus())
,这通常意味着执行connection.rollback()
。cleanupTransactionInfo()
- 清理现场:在
finally
块中,无论成功失败,都会清理ThreadLocal
中保存的事务信息。commitTransactionAfterReturning()
- 成功时提交:如果目标方法顺利执行完毕,没有抛出需要回滚的异常,此方法会被调用。
它会调用
ptm.commit(txInfo.getTransactionStatus())
,这通常意味着执行connection.commit()
。
至此,一个由 @Transactional
控制的事务,走完了它严谨而恢弘的一生。
第四章:总结——事务管理的本质
经过这次终极探险,@Transactional
在我们面前再无秘密可言。它的本质,是 Spring Framework 各大核心组件的一次完美协同作战:
- IoC 容器 (基础):
- 负责管理
PlatformTransactionManager
、DataSource
以及所有业务 Bean 的生命周期。 - Spring Boot 自动配置 (粘合剂):
- 智能地检测环境,自动为我们配置好
PlatformTransactionManager
,并启用事务 AOP 功能,将所有组件无缝地粘合在一起。 - Spring AOP (执行者):
- 作为事务的“代理人”,通过
TransactionInterceptor
在目标方法执行前后织入事务控制逻辑,这是整个事务管理得以“无侵入式”实现的关键。 PlatformTransactionManager
(抽象核心):- 这是 Spring 对不同事务资源(JDBC, JPA, JMS 等)的高度抽象。
TransactionInterceptor
只与这个接口打交道,从而屏蔽了底层的实现差异。 TransactionSynchronizationManager
(线程绑定):- 一个基于
ThreadLocal
的工具,它确保在同一个事务调用链中,所有部分获取到的都是同一个数据库连接 (Connection
) 和同一个事务状态,这是事务能够跨方法、跨 DAO 生效的保障。
从 IoC 的萌芽,到 AOP 的切入;从 MVC 的请求,到 Boot 的装配;再到今天,事务的保障。我们这场历时五章的 Spring 源码探险,至此画上了一个圆满的句号。
我们不再是浮于表面的 API 调用者。我们亲眼见证了 Bean 如何诞生,代理如何生成,请求如何流转,配置如何加载,事务如何控制。我们理解了 Spring 框架背后那些优雅、精妙、贯穿始终的设计思想——抽象、分层、扩展、约定。
Code Tells All. 源码,已经告诉了我们一切。
这次探险的终点,是你对 Spring 乃至所有优秀框架建立全新认知的起点。当你未来面对任何一个“黑盒”技术时,愿你都能拥有深入其源码、探究其本质的勇气和能力。
山高路远,江湖再见!