spring-reading./spring-transaction/spring-transaction-springTr...
linlei ef784196ba spring事务源码分析 2024-05-28 15:22:28 +08:00
..
src/main/java/com/xcs/spring spring事务源码分析 2024-05-28 15:22:28 +08:00
README.md spring事务源码分析 2024-05-28 15:22:28 +08:00
pom.xml spring事务源码分析 2024-05-28 15:22:28 +08:00

README.md

TransactionAnnotationParser

一、基本信息

✒️ 作者 - Lex 📝 博客 - 掘金 📚 **源码地址 ** - github

二、基本描述

TransactionAnnotationParser 接口是 Spring Framework 中的一个接口,用于定义解析事务相关注解的标准方式,我们可以通过实现该接口来自定义解析特定事务注解的逻辑,并将其转换为 Spring 内部的事务配置对象,以实现更灵活的事务管理。

三、主要功能

  1. 解析事务注解

    • 该接口定义了解析事务相关注解的方法,我们可以通过实现该方法来提取注解中的属性信息。
  2. 支持多种注解

    • 允许实现类支持多种事务相关的注解,不仅限于 @Transactional,这使得接口更加灵活和通用。
  3. 自定义扩展

    • 根据自己的需求实现该接口,并自定义解析逻辑,以满足特定场景下的事务管理需求,从而扩展 Spring Framework 的事务管理功能。

四、接口源码

用于解析已知的事务注解类型。它包括一个默认方法用于确定给定类是否是事务注解的候选类,以及一个方法用于解析给定方法或类上的事务注解并将其转换为 Spring 框架的事务属性对象。该接口的实现类可用于支持特定的事务注解类型,如 Spring 的 @Transactional、JTA 1.2 的 javax.transaction.Transactional 或 EJB3 的 javax.ejb.TransactionAttribute

/**
 * 已知事务注解类型解析的策略接口。
 * {@link AnnotationTransactionAttributeSource} 委托给此类解析器,以支持特定的注解类型,例如 Spring 的 {@link Transactional}、JTA 1.2 的 {@link javax.transaction.Transactional} 或 EJB3 的 {@link javax.ejb.TransactionAttribute}。
 *
 * @author Juergen Hoeller
 * @since 2.5
 * @see AnnotationTransactionAttributeSource
 * @see SpringTransactionAnnotationParser
 * @see Ejb3TransactionAnnotationParser
 * @see JtaTransactionAnnotationParser
 */
public interface TransactionAnnotationParser {

    /**
     * 确定给定类是否是此 {@code TransactionAnnotationParser} 的注解格式中的事务属性候选类。
     * <p>如果此方法返回 {@code false},则给定类上的方法将不会被遍历用于 {@code #parseTransactionAnnotation} 内省。
     * 返回 {@code false} 是针对未受影响的类的优化,而 {@code true} 意味着类需要对给定类上的每个方法进行完整的内省。
     * @param targetClass 要内省的类
     * @return 如果已知该类在类或方法级别上没有事务注解,则返回 {@code false};否则返回 {@code true}。默认实现返回 {@code true},导致常规内省。
     * @since 5.2
     */
    default boolean isCandidateClass(Class<?> targetClass) {
        return true;
    }

    /**
     * 根据此解析器理解的注解类型,解析给定方法或类的事务属性。
     * <p>本质上,这将已知的事务注解解析为 Spring 的元数据属性类。如果方法/类不是事务性的,则返回 {@code null}。
     * @param element 被注解的方法或类
     * @return 配置的事务属性,如果没有找到则返回 {@code null}
     * @see AnnotationTransactionAttributeSource#determineTransactionAttribute
     */
    @Nullable
    TransactionAttribute parseTransactionAnnotation(AnnotatedElement element);

}

五、主要实现

  1. SpringTransactionAnnotationParser

    • 用于解析 Spring Framework 中的 @Transactional 注解,它能够将 @Transactional 注解中的属性信息提取出来,并转换为 Spring 内部的事务配置对象。在 Spring 应用中,通常使用 @Transactional 注解声明事务,因此这个解析器是非常常用的,它使得事务管理更加便捷和灵活。
  2. Ejb3TransactionAnnotationParser

    • 用于解析 EJB3 规范中的 javax.ejb.TransactionAttribute 注解。EJB3 是 Java EE 规范中的一部分,用于开发企业级应用程序。Ejb3TransactionAnnotationParser 负责解析 javax.ejb.TransactionAttribute 注解,并将其转换为 Spring 内部的事务配置对象,这使得 Spring 能够与 EJB3 技术集成,实现统一的事务管理。
  3. JtaTransactionAnnotationParser

    • 用于解析 JTAJava Transaction API规范中定义的 javax.transaction.Transactional 注解。JTA 是 Java 平台的一部分,提供了一套 API 用于管理分布式事务。JtaTransactionAnnotationParser 负责解析 javax.transaction.Transactional 注解,并将其转换为 Spring 内部的事务配置对象,这使得 Spring 能够与分布式事务相关的技术集成,实现全面的事务管理支持。

六、类关系图

classDiagram
direction BT
class Ejb3TransactionAnnotationParser
class JtaTransactionAnnotationParser
class SpringTransactionAnnotationParser
class TransactionAnnotationParser {
<<Interface>>

}

Ejb3TransactionAnnotationParser  ..>  TransactionAnnotationParser 
JtaTransactionAnnotationParser  ..>  TransactionAnnotationParser 
SpringTransactionAnnotationParser  ..>  TransactionAnnotationParser 

七、最佳实践

使用 SpringTransactionAnnotationParser 类来解析方法上的事务注解,并将其转换为事务属性对象。在这个示例中,通过反射获取了 ScoresServiceImpl 类中的 insertScore 方法,然后通过 SpringTransactionAnnotationParser 解析该方法上的事务注解,最后将解析结果输出到控制台。

public class SpringTransactionAnnotationParserDemo {

    public static void main(String[] args) throws NoSuchMethodException {
        // 获取 ScoresServiceImpl 类中的 insertScore 方法
        Method insertScoreMethod = ScoresServiceImpl.class.getMethod("insertScore");
        // 创建 SpringTransactionAnnotationParser 实例
        SpringTransactionAnnotationParser parser = new SpringTransactionAnnotationParser();
        // 解析 insertScore 方法上的事务注解,并转换为事务属性对象
        TransactionAttribute transactionAttribute = parser.parseTransactionAnnotation(insertScoreMethod);
        // 输出事务属性对象
        System.out.println(transactionAttribute);
    }
}

ScoresServiceImpl 类实现了 ScoresService 接口,其中的 insertScore 方法被 @Transactional 注解修饰声明了一个事务。该事务的特性包括只读readOnly = true遇到任何异常都会回滚rollbackFor = Exception.class事务隔离级别为可重复读isolation = Isolation.REPEATABLE_READ超时时间为 30 秒timeout = 30以及标签为 "tx1" 和 "tx2"。

public class ScoresServiceImpl implements ScoresService {

    @Override
    @Transactional(
            readOnly = true,
            rollbackFor = Exception.class,
            isolation = Isolation.REPEATABLE_READ,
            timeout = 30,
            label = {"tx1", "tx2"}
    )
    public void insertScore() {
        // TODO
    }
}

运行结果,事务的传播行为为 PROPAGATION_REQUIRED,隔离级别为 ISOLATION_REPEATABLE_READ,超时时间为 30 秒,只读模式开启,标签为 "tx1" 和 "tx2",同时,事务会回滚遇到 java.lang.Exception 及其子类的异常。

PROPAGATION_REQUIRED,ISOLATION_REPEATABLE_READ,timeout_30,readOnly; [tx1,tx2],-java.lang.Exception

八、源码分析

org.springframework.transaction.annotation.SpringTransactionAnnotationParser#parseTransactionAnnotation(java.lang.reflect.AnnotatedElement) 方法中,首先通过 AnnotatedElementUtils 查找并获取元素上合并的 @Transactional 注解的属性信息,如果找到了注解,则调用另一个方法解析事务注解并返回事务属性对象,如果未找到注解,则返回 null。


@Override
@Nullable
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
    // 查找并获取元素上合并的 @Transactional 注解的属性信息
    AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
            element, Transactional.class, false, false);
    // 如果属性信息不为空,则解析事务注解并返回事务属性对象
    if (attributes != null) {
        return parseTransactionAnnotation(attributes);
    }
    // 如果属性信息为空,则返回 null
    else {
        return null;
    }
}

org.springframework.transaction.annotation.SpringTransactionAnnotationParser#parseTransactionAnnotation(org.springframework.core.annotation.AnnotationAttributes) 方法中,用于解析给定的注解属性并将其转换为事务属性对象。它根据注解属性中的信息设置事务的传播行为、隔离级别、超时时间、只读属性、限定符、标签和回滚规则等。最后,它返回一个基于规则的事务属性对象。

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(Arrays.asList(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;
}