跳转至

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的机制。

2_✅介绍一下Spring的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 实现的事务的主要原理。