Spring中@Transactional事务的实现原理¶
操作,典型回答¶
Spring的@Transactional事务的核心原理可以概括为 “通过 AOP(面向切面编程)创建代理对象,并在方法调用前后介入事务管理逻辑”。整个实现过程可以分为以下几步:
- 注解解析:Spring 会在启动时扫描被
@Transactional注解标记的类或方法,通过AnnotationTransactionAttributeSource类解析注解的属性,并将这些属性传递给事务拦截器。 - 代理创建:通过
TransactionProxyFactoryBean为被标注为@Transactional的方法创建代理对象。 - 事务拦截:代理对象会通过
TransactionInterceptor拦截方法的调用,执行事务的启动、提交或回滚等操作。 - 事务管理:
TransactionInterceptor调用PlatformTransactionManager来启动、提交和回滚事务。- 如果
@Transactional方法执行成功,则提交事务 - 如果
@Transactional方法执行出现异常,则回滚事务
- 如果
注解解析¶
我们想要让一个方法在事务中,只需要在方法上加一个@Transactional 就行了,那么这个注解是起到了怎样的作用呢?
其实,在 Spring 启动时,它会通过扫描类路径上的所有 Bean,将那些标注了 @Transactional 注解的类或方法标记为事务管理目标。
SpringTransactionAnnotationParser用来解析 @Transactional 注解中的属性(比如传播行为、隔离级别等),并将这些属性转化为 Spring 管理事务所需的配置。这些解析的结果最终会传递给 TransactionInterceptor,后者负责执行事务的具体操作。
protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
// 解析传播行为
Propagation propagation = attributes.getEnum("propagation");
rbta.setPropagationBehavior(propagation.value());
// 解析隔离级别
Isolation isolation = attributes.getEnum("isolation");
rbta.setIsolationLevel(isolation.value());
// 解析超时时间
rbta.setTimeout(attributes.getNumber("timeout").intValue());
String timeoutString = attributes.getString("timeoutString");
Assert.isTrue(!StringUtils.hasText(timeoutString) || rbta.getTimeout() < 0,
"Specify 'timeout' or 'timeoutString', not both");
rbta.setTimeoutString(timeoutString);
// 解析是否只读
rbta.setReadOnly(attributes.getBoolean("readOnly"));
rbta.setQualifier(attributes.getString("value"));
rbta.setLabels(Set.of(attributes.getStringArray("label")));
// 解析回滚规则
List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
rollbackRules.add(new RollbackRuleAttribute(rbRule));
}
for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
rollbackRules.add(new RollbackRuleAttribute(rbRule));
}
for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) {
rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
}
for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {
rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
}
rbta.setRollbackRules(rollbackRules);
return rbta;
}
代理创建¶
Spring容器在启动的过程中,会给使用了@Transactional注解的类创建一个代理对象,后续的所有的事务方法的调用,都会先通过代理对象进行调用(对象内部的自调用(this)调用除外)。
具体的代理对象的创建过程,直接看AOP的实现原理即可,一样的,因为这里用的就是AOP的机制。
这个代理对象实际上是使用 JDK 动态代理或 CGLIB 代理生成的,它会拦截对目标对象的调用,决定是否开始事务,方法执行后是否提交或者回滚事务。
事务拦截&管理¶
有了代理对象了之后,就需要在事务方法调用的过程中做事务拦截操作。TransactionInterceptor 是 Spring 中事务管理的核心部分,它实现了 MethodInterceptor 接口,负责拦截目标方法的调用。TransactionInterceptor 会在方法执行之前检查事务的相关配置(如传播行为、隔离级别等),并根据这些配置开始、提交或回滚事务。
@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
// 获取目标类
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// 关键:在事务中执行
return invokeWithinTransaction(invocation.getMethod(), targetClass, new CoroutinesInvocationCallback() {
@Override
@Nullable
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
@Override
public Object getTarget() {
return invocation.getThis();
}
@Override
public Object[] getArguments() {
return invocation.getArguments();
}
});
}
invokeWithinTransaction是TransactionAspectSupport中的一个方法,这个方法很关键:
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 ptm = determineTransactionManager(txAttr);
// .... 省略部分代码
// 3. 构建方法标识(用于日志等)
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
// 4. 处理声明式事务
if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
// 4.1 创建事务(这是关键!)
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
Object retVal;
try {
// 4.2 执行目标业务方法
retVal = invocation.proceedWithInvocation();
} catch (Throwable ex) {
// 4.3 异常回滚处理
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
} finally {
// 清理事务信息
cleanupTransactionInfo(txInfo);
}
// ... 省略部分代码
// 4.4 提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
}
// ... 编程式事务处理
}
所以,可以看到,这里其实就是非常核心的事务处理的过程了:
1、开启事务
2、执行目标方法
3、如果执行成功,则提交事务
4、如果执行过程中出现异常,则回滚事务
以上,就是Spring中的@Transactional 实现的事务的主要原理。