【小家Spring】源码分析Spring的事务拦截器:TransactionInterceptor和事务管理器:PlatformTransactionManager(中)

简介: 【小家Spring】源码分析Spring的事务拦截器:TransactionInterceptor和事务管理器:PlatformTransactionManager(中)

TransactionAspectSupport.TransactionInfo:内部类 事务Info


它是TransactionAspectSupport的一个protected内部类。我觉得有必要先讲解下它:

  protected final class TransactionInfo {
    // 当前事务  的事务管理器
    @Nullable
    private final PlatformTransactionManager transactionManager;
    // 当前事务  的事务属性
    @Nullable
    private final TransactionAttribute transactionAttribute;
    // joinpoint标识
    private final String joinpointIdentification;
    // 当前事务   的TransactionStatus 
    @Nullable
    private TransactionStatus transactionStatus;
    // 重点就是这个oldTransactionInfo字段
    // 这个字段保存了当前事务所在的`父事务`上下文的引用,构成了一个链,准确的说是一个有向无环图
    @Nullable
    private TransactionInfo oldTransactionInfo;
    // 唯一的构造函数~~~~
    public TransactionInfo(@Nullable PlatformTransactionManager transactionManager, @Nullable TransactionAttribute transactionAttribute, String joinpointIdentification) {
      this.transactionManager = transactionManager;
      this.transactionAttribute = transactionAttribute;
      this.joinpointIdentification = joinpointIdentification;
    }
    public PlatformTransactionManager getTransactionManager() {
      Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
      return this.transactionManager;
    }
    // 注意这个方法名,新的一个事务status
    public void newTransactionStatus(@Nullable TransactionStatus status) {
      this.transactionStatus = status;
    }
    public boolean hasTransaction() {
      return (this.transactionStatus != null);
    }
    //绑定当前正在处理的事务的所有信息到ThreadLocal
    private void bindToThread() {
      // Expose current TransactionStatus
      // 老的事务  先从线程中拿出来,再把新的(也就是当前)绑定进去~~~~~~
      this.oldTransactionInfo = transactionInfoHolder.get();
      transactionInfoHolder.set(this);
    }
    // 当前事务处理完之后,恢复父事务上下文
    private void restoreThreadLocalStatus() {
      transactionInfoHolder.set(this.oldTransactionInfo);
    }
    @Override
    public String toString() {
      return (this.transactionAttribute != null ? this.transactionAttribute.toString() : "No transaction");
    }
  }


了解了这个Info内部类之后,接下来可议看看TransactionAspectSupport#createTransactionIfNecessary方法:它是创建事务的一个重要方法。


它会判断是否存在事务,根据事务的传播属性。做出不同的处理,也是做了一层包装,核心是通过TransactionStatus来判断事务的属性


创建事务:createTransactionIfNecessary()

  // 若有需要 创建一个TransactionInfo (具体的事务从事务管理器里面getTransaction()出来~)
  protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
      @Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
    // If no name specified, apply method identification as transaction name.
    // 这个简单的说,就是给Name赋值~~~~~
    if (txAttr != null && txAttr.getName() == null) {
      txAttr = new DelegatingTransactionAttribute(txAttr) {
        @Override
        public String getName() {
          return joinpointIdentification;
        }
      };
    }
    // 从事务管理器里,通过txAttr拿出来一个TransactionStatus
    TransactionStatus status = null;
    if (txAttr != null) {
      if (tm != null) {
        status = tm.getTransaction(txAttr);
      }
      ...
    }
    // 通过TransactionStatus 等,转换成一个通用的TransactionInfo
    return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
  }


准备事务:prepareTransactionInfo()


  protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm,
      @Nullable TransactionAttribute txAttr, String joinpointIdentification,
      @Nullable TransactionStatus status) {
    // 构造一个TransactionInfo 
    TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
    if (txAttr != null) {
      // 如果已存在不兼容的Tx,事务管理器将标记错误
      txInfo.newTransactionStatus(status);
    }
    ,..
    // We always bind the TransactionInfo to the thread, even if we didn't create
    // a new transaction here. This guarantees that the TransactionInfo stack
    // will be managed correctly even if no transaction was created by this aspect.
    // 这句话是最重要的:把生成的TransactionInfo并绑定到当前线程的ThreadLocal
    txInfo.bindToThread();
    return txInfo;
  }

提交事务:commitTransactionAfterReturning()


  //比较简单  只用用事务管理器提交事务即可~~~  具体的实现逻辑在事务管理器的commit实现里~~~
  protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
    if (txInfo != null && txInfo.getTransactionStatus() != null) {
      txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
    }
  }


回滚事务:completeTransactionAfterThrowing()


  protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
    if (txInfo != null && txInfo.getTransactionStatus() != null) {
      // 如果有事务属性了,那就调用rollbackOn看看这个异常需不需要回滚
      if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
        try {
          txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
        }
        ...
      }
      // 编程式事务没有事务属性,那就commit吧
      else {
        try {
          txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
        }
        ...
      }
    }
  }


清除(解绑)事务:cleanupTransactionInfo()


  protected void cleanupTransactionInfo(@Nullable TransactionInfo txInfo) {
    if (txInfo != null) {
      txInfo.restoreThreadLocalStatus();
    }
  }


PlatformTransactionManager:事务管理器


记下硕说另外一大块内容:事务管理器。谈到事务,肯定是离不开它的。

关于事务管理器,不管是JPA(JpaTransactionManager )还是JDBC(DataSourceTransactionManager)甚至是JTA(JtaTransactionManager)等都实现自接口 PlatformTransactionManager


它只提供三个方法:


public interface PlatformTransactionManager {
  TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;
  void commit(TransactionStatus status) throws TransactionException;
  void rollback(TransactionStatus status) throws TransactionException;


这三个方法就不用再多说。


image.png


下面以最常用的实现:DataSourceTransactionManager 做源码分析~~~

先看看它的抽象实现:AbstractPlatformTransactionManager,这个抽象类提供了处理的模版(其实Spring的设计模式中,很多抽象类都提供了实现模版),然后提供开口给子类去各自实现~


AbstractPlatformTransactionManager


可见它是对PlatformTransactionManager的一个抽象实现。实现Spring的标准事务工作流

这个基类提供了以下工作流程处理:


  • 确定如果有现有的事务;
  • 应用适当的传播行为;
  • 如果有必要暂停和恢复事务;
  • 提交时检查rollback-only标记;
  • 应用适当的修改当回滚(实际回滚或设置rollback-only);
  • 触发同步回调注册(如果事务同步是激活的)


public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable {
  //始终激活事务同步(请参阅事务的传播属性~)
  public static final int SYNCHRONIZATION_ALWAYS = 0;
  //仅对实际事务(即,不针对由传播导致的空事务)激活事务同步\不支持现有后端事务
  public static final int SYNCHRONIZATION_ON_ACTUAL_TRANSACTION = 1;
  //永远不激活事务同步
  public static final int SYNCHRONIZATION_NEVER = 2;
  // 相当于把本类的所有的public static final的变量都收集到此处~~~~
  private static final Constants constants = new Constants(AbstractPlatformTransactionManager.class);
  // ===========默认值
  private int transactionSynchronization = SYNCHRONIZATION_ALWAYS;
  // 事务默认的超时时间  为-1表示不超时
  private int defaultTimeout = TransactionDefinition.TIMEOUT_DEFAULT;
  //Set whether nested transactions are allowed. Default is "false".
  private boolean nestedTransactionAllowed = false;
  // Set whether existing transactions should be validated before participating(参与、加入)
  private boolean validateExistingTransaction = false;
  //设置是否仅在参与事务`失败后`将 现有事务`全局`标记为回滚  默认值是true 需要注意~~~
  // 表示只要你的事务失败了,就标记此事务为rollback-only 表示它只能给与回滚  而不能再commit或者正常结束了
  // 这个调用者经常会犯的一个错误就是:上层事务service抛出异常了,自己把它给try住,并且并且还不throw,那就肯定会报错的:
  // 报错信息:Transaction rolled back because it has been marked as rollback-only
  // 当然喽,这个属性强制不建议设置为false~~~~~~
  private boolean globalRollbackOnParticipationFailure = true;
  // 如果事务被全局标记为仅回滚,则设置是否及早失败~~~~
  private boolean failEarlyOnGlobalRollbackOnly = false;
  // 设置在@code docommit调用失败时是否应执行@code dorollback 通常不需要,因此应避免
  private boolean rollbackOnCommitFailure = false;
  // 此处我们直接可以通过属性们来社会,语意思更清晰些了
  // 我们发现使用起来有点枚举的意思了,特别是用XML配置的时候  非常像枚举的使用~~~~~~~
  // 这也是Constants的重要意义~~~~
  public final void setTransactionSynchronizationName(String constantName) {
    setTransactionSynchronization(constants.asNumber(constantName).intValue());
  }
  public final void setTransactionSynchronization(int transactionSynchronization) {
    this.transactionSynchronization = transactionSynchronization;
  }
  //... 省略上面所有字段的一些get/set方法~~~
  // 最为重要的一个方法,根据实物定义,获取到一个事务TransactionStatus 
  @Override
  public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
    //doGetTransaction()方法是抽象方法,具体的实现由具体的事务处理器提供(下面会以DataSourceTransactionManager为例子)
    Object transaction = doGetTransaction();
    //如果没有配置事务属性,则使用默认的事务属性
    if (definition == null) {
      definition = new DefaultTransactionDefinition();
    }
    //检查当前线程是否存在事务  isExistingTransaction此方法默认返回false  但子类都复写了此方法
    if (isExistingTransaction(transaction)) {
      // handleExistingTransaction方法为处理已经存在事务的情况
      // 这个方法的实现也很复杂,总之还是对一些传播属性进行解析,各种情况的考虑~~~~~ 如果有新事务产生 doBegin()就会被调用~~~~
      return handleExistingTransaction(definition, transaction, debugEnabled);
    }
    // 超时时间的简单校验~~~~
    if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
      throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
    }
    // 处理事务属性中配置的事务传播特性==============
    // PROPAGATION_MANDATORY 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常
    if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
      throw new IllegalTransactionStateException("No existing transaction found for transaction marked with propagation 'mandatory'");
    }
    //如果事务传播特性为required、required_new或nested
    else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
        definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
        definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
      // 挂起,但是doSuspend()由子类去实现~~~
      // 挂起操作,触发相关的挂起注册的事件,把当前线程事物的所有属性都封装好,放到一个SuspendedResourcesHolder
      // 然后清空清空一下`当前线程事务`
      SuspendedResourcesHolder suspendedResources = suspend(null);
      // 此处,开始创建事务~~~~~
      try {
        boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
        // //创建一个新的事务状态  就是new DefaultTransactionStatus()  把个属性都赋值上
        DefaultTransactionStatus status = newTransactionStatus(
            definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
        // 开始事务,抽象方法,由子类去实现~
        doBegin(transaction, definition);
        //初始化和同步事务状态    是TransactionSynchronizationManager这个类  它内部维护了很多的ThreadLocal
        prepareSynchronization(status, definition);
        return status;
      }
      catch (RuntimeException | Error ex) {
        //重新开始 doResume由子类去实现
        resume(null, suspendedResources);
        throw ex;
      }
    }
    // 走到这里  传播属性就是不需要事务的  那就直接创建一个
    else {
      boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
      // 这个方法相当于先newTransactionStatus,再prepareSynchronization这两步~~~
      // 显然和上面的区别是:中间不回插入调用doBegin()方法,因为没有事务  begin个啥~~
      return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
    }
  }
  // 再看看commit方法
  @Override
  public final void commit(TransactionStatus status) throws TransactionException {
    //如果是一个已经完成的事物,不可重复提交
    if (status.isCompleted()) {
      throw new IllegalTransactionStateException("Transaction is already completed - do not call commit or rollback more than once per transaction");
    }
    DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
    // 如果已经标记为了需要回滚,那就执行回滚吧
    if (defStatus.isLocalRollbackOnly()) {
      processRollback(defStatus, false);
      return;
    }
    //  shouldCommitOnGlobalRollbackOnly这个默认值是false,目前只有JTA事务复写成true了
    // isGlobalRollbackOnly:是否标记为了全局的RollbackOnly
    if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
      processRollback(defStatus, true);
      return;
    }
    // 提交事务   这里面还是挺复杂的,会考虑到还原点、新事务、事务是否是rollback-only之类的~~
    processCommit(defStatus);
  }
  // rollback方法  里面doRollback方法交给子类去实现~~~
  @Override
  public final void rollback(TransactionStatus status) throws TransactionException {
    DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
    processRollback(defStatus, false);
  }
}


从这个抽象类源码分析可以看出,它绝对是一个非常非常典型的模版实现,各个方法实现都是这样。自己先提供实现模版,很多具体的实现方案都开放给子类,比如begin,suspend, resume, commit, rollback等,相当于留好了众多的连接点


这个类的抽象程度非常的高,逻辑也非常的复杂。要想绝对的理解到位,必须要对JDBC的事务非常了解,而且还对这些代码逻辑必须进行精读。书读百遍,其义自见

相关文章
|
2月前
|
监控 Java 应用服务中间件
Spring Boot整合Tomcat底层源码分析
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置和起步依赖等特性,大大简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是其与Tomcat的整合。
78 1
|
1月前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
19天前
|
SQL Java 关系型数据库
【SpringFramework】Spring事务
本文简述Spring中数据库及事务相关衍伸知识点。
45 9
|
26天前
|
Java 开发者 Spring
理解和解决Spring框架中的事务自调用问题
事务自调用问题是由于 Spring AOP 代理机制引起的,当方法在同一个类内部自调用时,事务注解将失效。通过使用代理对象调用、将事务逻辑分离到不同类中或使用 AspectJ 模式,可以有效解决这一问题。理解和解决这一问题,对于保证 Spring 应用中的事务管理正确性至关重要。掌握这些技巧,可以提高开发效率和代码的健壮性。
86 13
|
1月前
|
缓存 安全 Java
Spring高手之路26——全方位掌握事务监听器
本文深入探讨了Spring事务监听器的设计与实现,包括通过TransactionSynchronization接口和@TransactionalEventListener注解实现事务监听器的方法,并通过实例详细展示了如何在事务生命周期的不同阶段执行自定义逻辑,提供了实际应用场景中的最佳实践。
56 2
Spring高手之路26——全方位掌握事务监听器
|
2月前
|
XML Java 数据库连接
Spring高手之路25——深入解析事务管理的切面本质
本篇文章将带你深入解析Spring事务管理的切面本质,通过AOP手动实现 @Transactional 基本功能,并探讨PlatformTransactionManager的设计和事务拦截器TransactionInterceptor的工作原理,结合时序图详细展示事务管理流程,最后引导分析 @Transactional 的代理机制源码,帮助你全面掌握Spring事务管理。
46 2
Spring高手之路25——深入解析事务管理的切面本质
|
1月前
|
Java 关系型数据库 数据库
京东面试:聊聊Spring事务?Spring事务的10种失效场景?加入型传播和嵌套型传播有什么区别?
45岁老架构师尼恩分享了Spring事务的核心知识点,包括事务的两种管理方式(编程式和声明式)、@Transactional注解的五大属性(transactionManager、propagation、isolation、timeout、readOnly、rollbackFor)、事务的七种传播行为、事务隔离级别及其与数据库隔离级别的关系,以及Spring事务的10种失效场景。尼恩还强调了面试中如何给出高质量答案,推荐阅读《尼恩Java面试宝典PDF》以提升面试表现。更多技术资料可在公众号【技术自由圈】获取。
|
2月前
|
监控 Java 数据安全/隐私保护
如何用Spring Boot实现拦截器:从入门到实践
如何用Spring Boot实现拦截器:从入门到实践
67 5
|
2月前
|
JavaScript Java 关系型数据库
Spring事务失效的8种场景
本文总结了使用 @Transactional 注解时事务可能失效的几种情况,包括数据库引擎不支持事务、类未被 Spring 管理、方法非 public、自身调用、未配置事务管理器、设置为不支持事务、异常未抛出及异常类型不匹配等。针对这些情况,文章提供了相应的解决建议,帮助开发者排查和解决事务不生效的问题。
|
4天前
|
XML Java 应用服务中间件
Spring Boot 两种部署到服务器的方式
本文介绍了Spring Boot项目的两种部署方式:jar包和war包。Jar包方式使用内置Tomcat,只需配置JDK 1.8及以上环境,通过`nohup java -jar`命令后台运行,并开放服务器端口即可访问。War包则需将项目打包后放入外部Tomcat的webapps目录,修改启动类继承`SpringBootServletInitializer`并调整pom.xml中的打包类型为war,最后启动Tomcat访问应用。两者各有优劣,jar包更简单便捷,而war包适合传统部署场景。需要注意的是,war包部署时,内置Tomcat的端口配置不会生效。
92 17
Spring Boot 两种部署到服务器的方式