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

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

前言


接着上一篇博文:

【小家Spring】从基于@Transactional全注解方式的声明式事务入手,彻底掌握Spring事务管理的原理


TransactionInterceptor作为它的增强子,扮演着增强处理Spring事务的核心角色。上篇博文篇幅有限,且为了突出TransactionInterceptor和PlatformTransactionManager的重要性,因此本文专门列专文专题讲解~


TransactionInterceptor支撑着整个事务功能的架构,逻辑还是相对复杂的,那么现在我们切入正题来分析此拦截器是如何实现事务特性的。


Spring事务三大接口回顾


在spring的事务管理高层抽象层中主要包含3个接口:


TransactionDefinition:用于描述隔离级别、超时时间、是否为只读事务和事务传播规则


TransactionStatus:代表一个事务的具体运行状态、以及还原点


PlatformTransactionManager:一个高层次的接口,包含3个方法。commit、rollback和getTramsaction


TransactionStatus



在讲解拦截器的执行过程之前,先得了解Spring抽象出来的这个接口。它表示事务的状态。


若有需要,事务代码可以使用它来检索状态信息,以编程方式请求回滚(而不是抛出导致隐式回滚的异常)


// 可以看到它继承自SavepointManager,所以它也会处理还原点
public interface TransactionStatus extends SavepointManager, Flushable {
  // 判断当前的事务是否是新事务
  boolean isNewTransaction();
  // 判断该事务里面是否含有还原点~
  boolean hasSavepoint();
  // Set the transaction rollback-only
  // 这是了这个,事务的唯一结果是进行回滚。因此如果你在外层给try catche住不让事务回滚,就会抛出你可能常见的异常:
  // Transaction rolled back because it has been marked as rollback-only
  void setRollbackOnly();
  boolean isRollbackOnly();
  //将基础会话刷新到数据存储 for example, all affected Hibernate/JPA sessions
  @Override 
  void flush();
  // Return whether this transaction is completed
  // 不管是commit或者rollback了都算结束了~~~
  boolean isCompleted();
}


它的继承体系:


image.png


AbstractTransactionStatus


它基本上是对接口进行了一些默认实现:


// @since 1.2.3 
public abstract class AbstractTransactionStatus implements TransactionStatus {
  // 两个标志位
  private boolean rollbackOnly = false;
  private boolean completed = false;
  // 一个还原点
  @Nullable
  private Object savepoint;
  // 把该属性值保存为true
  @Override
  public void setRollbackOnly() {
    this.rollbackOnly = true;
  }
  // 注意此处并不是直接读取
  @Override
  public boolean isRollbackOnly() {
    return (isLocalRollbackOnly() || isGlobalRollbackOnly());
  }
  public boolean isLocalRollbackOnly() {
    return this.rollbackOnly;
  }
  // Global这里返回false 但是子类DefaultTransactionStatus复写了此方法
  public boolean isGlobalRollbackOnly() {
    return false;
  }
  // 啥都没做  也是由子类去实现
  @Override
  public void flush() {
  }
  ...
}

下面看看两个具体类的实现:


SimpleTransactionStatus


public class SimpleTransactionStatus extends AbstractTransactionStatus {
  private final boolean newTransaction;
  // 构造函数
  public SimpleTransactionStatus() {
    this(true);
  }
  public SimpleTransactionStatus(boolean newTransaction) {
    this.newTransaction = newTransaction;
  }
  @Override
  public boolean isNewTransaction() {
    return this.newTransaction;
  }
}

它的实现太简单了,就是标志一下事务是否是新的事务。


SimpleTransactionStatus在Spring内部目前还没有使用场景~


DefaultTransactionStatus


public class DefaultTransactionStatus extends AbstractTransactionStatus {
  // 它有很多的标志位,成员变量  
  @Nullable
  private final Object transaction;
  // 是否是新事务
  private final boolean newTransaction;
  // 如果为给定事务打开了新的事务同步  该值为true
  private final boolean newSynchronization;
  // 该事务是否标记为了只读
  private final boolean readOnly;
  private final boolean debug;
  @Nullable
  private final Object suspendedResources;
  // 它的唯一构造函数如下:
  public DefaultTransactionStatus(@Nullable Object transaction, boolean newTransaction, boolean newSynchronization,
      boolean readOnly, boolean debug, @Nullable Object suspendedResources) {
    this.transaction = transaction;
    this.newTransaction = newTransaction;
    this.newSynchronization = newSynchronization;
    this.readOnly = readOnly;
    this.debug = debug;
    this.suspendedResources = suspendedResources;
  }
  // 直接把底层事务返回
  public Object getTransaction() {
    Assert.state(this.transaction != null, "No transaction active");
    return this.transaction;
  }
  public boolean hasTransaction() {
    return (this.transaction != null);
  }
  // 首先
  @Override
  public boolean isNewTransaction() {
    return (hasTransaction() && this.newTransaction);
  }
  ...
  // 都由SmartTransactionObject去处理  该接口的实现类有:
  // JdbcTransactionObjectSupport和JtaTransactionObject(分布式事务)
  public boolean isGlobalRollbackOnly() {
    return ((this.transaction instanceof SmartTransactionObject) &&
        ((SmartTransactionObject) this.transaction).isRollbackOnly());
  }
  @Override
  public void flush() {
    if (this.transaction instanceof SmartTransactionObject) {
      ((SmartTransactionObject) this.transaction).flush();
    }
  }
}


该DefaultTransactionStatus是Spring默认使用的事务状态,后面会有很多的接触~


对TransactionStatus有了了解之后,现在正式进去到TransactionInterceptor里


TransactionInterceptor:事务拦截器


我们已经知道了,它是个MethodInterceptor,被事务拦截的方法最终都会执行到此增强器身上。

MethodInterceptor是个环绕通知,敲好符合我们的开启、提交、回滚事务等操作~

public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
  // 构造函数:
  // 可议不用特殊的指定PlatformTransactionManager 事务管理器,后面会讲解自定义去获取
  // 可议自己指定Properties 以及 TransactionAttributeSource 
  public TransactionInterceptor() {
  }
  public TransactionInterceptor(PlatformTransactionManager ptm, Properties attributes) {
    setTransactionManager(ptm);
    setTransactionAttributes(attributes);
  }
  public TransactionInterceptor(PlatformTransactionManager ptm, TransactionAttributeSource tas) {
    setTransactionManager(ptm);
    setTransactionAttributeSource(tas);
  }
  // 接下来就是这个invoke方法:就是拦截的入口~
  @Override
  @Nullable
  public Object invoke(MethodInvocation invocation) throws Throwable {
    // 获取目标类
    Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
    // invokeWithinTransaction:父类TransactionAspectSupport的模板方法
    // invocation::proceed本处执行完成  执行目标方法(当然可能还有其余增强器)
    return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
  }
  ...
}


可以看出,真正做事情的其实还是在父类,它有一个执行事务的模版。


TransactionAspectSupport


// 通过BeanFactoryAware获取到BeanFactory
// InitializingBean的afterPropertiesSet是对Bean做一些验证(经常会借助它这么来校验Bean~~~)
public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {
  // 这个类不允许实现Serializable接口,请注意~~
  // NOTE: This class must not implement Serializable because it serves as base
  // class for AspectJ aspects (which are not allowed to implement Serializable)!
  /**
   * Key to use to store the default transaction manager.
   */
  private static final Object DEFAULT_TRANSACTION_MANAGER_KEY = new Object();
  // currentTransactionStatus() 方法依托于它
  private static final ThreadLocal<TransactionInfo> transactionInfoHolder = new NamedThreadLocal<>("Current aspect-driven transaction");
  //Subclasses can use this to return the current TransactionInfo.
  // Only subclasses that cannot handle all operations in one method
  // 注意此方法是个静态方法  并且是protected的  说明只有子类能够调用,外部并不可以~~~
  @Nullable
  protected static TransactionInfo currentTransactionInfo() throws NoTransactionException {
    return transactionInfoHolder.get();
  }
  // 外部调用此Static方法,可议获取到当前事务的状态  从而甚至可议手动来提交、回滚事务
  public static TransactionStatus currentTransactionStatus() throws NoTransactionException {
    TransactionInfo info = currentTransactionInfo();
    if (info == null || info.transactionStatus == null) {
      throw new NoTransactionException("No transaction aspect-managed TransactionStatus in scope");
    }
    return info.transactionStatus;
  }
  //==========================================
  // 事务管理器的名称(若设置,会根据此名称去找到事务管理器~~~~)
  @Nullable
  private String transactionManagerBeanName;
  @Nullable
  private PlatformTransactionManager transactionManager;
  @Nullable
  private TransactionAttributeSource transactionAttributeSource;
  @Nullable
  private BeanFactory beanFactory;
  // 因为事务管理器可能也会有多个  所以此处做了一个简单的缓存~
  private final ConcurrentMap<Object, PlatformTransactionManager> transactionManagerCache = new ConcurrentReferenceHashMap<>(4);
  public void setTransactionAttributeSource(@Nullable TransactionAttributeSource transactionAttributeSource) {
    this.transactionAttributeSource = transactionAttributeSource;
  }
  // 这部操作发现,若传入的为Properties  内部是实际使用的是NameMatchTransactionAttributeSource 去匹配的
  // 备注:若调用了此方法   transactionAttributeSource就会被覆盖的哟
  public void setTransactionAttributes(Properties transactionAttributes) {
    NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource();
    tas.setProperties(transactionAttributes);
    this.transactionAttributeSource = tas;
  }
  // 若你有多种匹配策略,这也是支持的  可谓非常强大有木有~~~
  public void setTransactionAttributeSources(TransactionAttributeSource... transactionAttributeSources) {
    this.transactionAttributeSource = new CompositeTransactionAttributeSource(transactionAttributeSources);
  }
  ...
  // 接下来就只剩我们最为核心的处理事务的模版方法了:
  //protected修饰,不允许其他包和无关类调用
  @Nullable
  protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, final InvocationCallback invocation) throws Throwable {
    // 获取事务属性源~
    TransactionAttributeSource tas = getTransactionAttributeSource();
    // 获取该方法对应的事务属性(这个特别重要)
    final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
    // 这个厉害了:就是去找到一个合适的事务管理器(具体策略详见方法~~~)
    final PlatformTransactionManager tm = determineTransactionManager(txAttr);
    // 拿到目标方法唯一标识(类.方法,如service.UserServiceImpl.save)
    final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
    // 如果txAttr为空或者tm 属于非CallbackPreferringPlatformTransactionManager,执行目标增强
    // 在TransactionManager上,CallbackPreferringPlatformTransactionManager实现PlatformTransactionManager接口,暴露出一个方法用于执行事务处理中的回调
    if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
      // 看是否有必要创建一个事务,根据`事务传播行为`,做出相应的判断
      TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
      Object retVal = null;
      try {
        //回调方法执行,执行目标方法(原有的业务逻辑)
        retVal = invocation.proceedWithInvocation();
      }
      catch (Throwable ex) {
        // 出现异常了,进行回滚(注意:并不是所有异常都会rollback的)
        // 备注:此处若没有事务属性   会commit 兼容编程式事务吧
        completeTransactionAfterThrowing(txInfo, ex);
        throw ex;
      }
      finally {
        //清除信息
        cleanupTransactionInfo(txInfo);
      }
      // 目标方法完全执行完成后,提交事务~~~
      commitTransactionAfterReturning(txInfo);
      return retVal;
    }
    //编程式事务处理(CallbackPreferringPlatformTransactionManager) 会走这里 
    // 原理也差不太多,这里不做详解~~~~
    else {
      final ThrowableHolder throwableHolder = new ThrowableHolder();
      // It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
      try {
        Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, status -> {
          TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
          try {
            return invocation.proceedWithInvocation();
          }
          catch (Throwable ex) {
            if (txAttr.rollbackOn(ex)) {
              // A RuntimeException: will lead to a rollback.
              if (ex instanceof RuntimeException) {
                throw (RuntimeException) ex;
              }
              else {
                throw new ThrowableHolderException(ex);
              }
            }
            else {
              // A normal return value: will lead to a commit.
              throwableHolder.throwable = ex;
              return null;
            }
          }
          finally {
            cleanupTransactionInfo(txInfo);
          }
        });
        // Check result state: It might indicate a Throwable to rethrow.
        if (throwableHolder.throwable != null) {
          throw throwableHolder.throwable;
        }
        return result;
      }
      catch (ThrowableHolderException ex) {
        throw ex.getCause();
      }
      catch (TransactionSystemException ex2) {
        if (throwableHolder.throwable != null) {
          logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
          ex2.initApplicationException(throwableHolder.throwable);
        }
        throw ex2;
      }
      catch (Throwable ex2) {
        if (throwableHolder.throwable != null) {
          logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
        }
        throw ex2;
      }
    }
  }
  // 从容器中找到一个事务管理器
  @Nullable
  protected PlatformTransactionManager determineTransactionManager(@Nullable TransactionAttribute txAttr) {
    // 如果这两个都没配置,所以肯定是手动设置了PlatformTransactionManager的,那就直接返回即可
    if (txAttr == null || this.beanFactory == null) {
      return getTransactionManager();
    }
    // qualifier 就在此处发挥作用了,他就相当于BeanName
    String qualifier = txAttr.getQualifier();
    if (StringUtils.hasText(qualifier)) {
      // 根据此名称 以及PlatformTransactionManager.class 去容器内招
      return determineQualifiedTransactionManager(this.beanFactory, qualifier);
    }
    // 若没有指定qualifier   那再看看是否指定了 transactionManagerBeanName
    else if (StringUtils.hasText(this.transactionManagerBeanName)) {
      return determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName);
    }
    // 若都没指定,那就不管了。直接根据类型去容器里找 getBean(Class)
    // 此处:若容器内有两个PlatformTransactionManager ,那就铁定会报错啦~~~
    else {
      PlatformTransactionManager defaultTransactionManager = getTransactionManager();
      if (defaultTransactionManager == null) {
        defaultTransactionManager = this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);
        if (defaultTransactionManager == null) {
          defaultTransactionManager = this.beanFactory.getBean(PlatformTransactionManager.class);
          this.transactionManagerCache.putIfAbsent(
              DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
        }
      }
      return defaultTransactionManager;
    }
  }
  // ======================================
}


不同的事务处理方式使用不同的逻辑。对于声明式事务的处理与编程式事务的处理,重要区别在于事务属性上,因为编程式的事务处理是不需要有事务属性的

上面处理事务的模版已经分析完成,下面单独摘出来分析一些具体的非常重要的方法。


相关文章
|
6月前
|
SQL Java 关系型数据库
Spring事务传播机制:7种姿势教你玩转"事务接力赛"
事务传播机制是Spring框架中用于管理事务行为的重要概念,它决定了在方法调用时事务如何传递与执行。通过7种传播行为,开发者可以灵活控制事务边界,适应不同业务场景。例如:REQUIRED默认加入或新建事务,REQUIRES_NEW独立开启新事务,NESTED支持嵌套回滚等。合理使用传播机制不仅能保障数据一致性,还能提升系统性能与健壮性。掌握这“七种人格”,才能在复杂业务中游刃有余。
|
5月前
|
监控 Java 数据库连接
《深入理解Spring》事务管理——数据一致性的守护者
Spring事务管理确保数据一致性,支持声明式与编程式两种方式。通过@Transactional注解简化配置,提供传播行为、隔离级别、回滚规则等灵活控制,结合ACID特性保障业务逻辑可靠执行。
|
5月前
|
缓存 监控 Java
《深入理解Spring》拦截器(Interceptor)——请求处理的艺术
Spring拦截器是Web开发中实现横切关注点的核心组件,基于AOP思想,可在请求处理前后执行日志记录、身份验证、权限控制等通用逻辑。相比Servlet过滤器,拦截器更贴近Spring容器,能访问Bean和上下文,适用于Controller级精细控制。通过实现`HandlerInterceptor`接口的`preHandle`、`postHandle`和`afterCompletion`方法,可灵活控制请求流程。结合配置类注册并设置路径匹配与执行顺序,实现高效复用与维护。常用于认证鉴权、性能监控、统一异常处理等场景,提升应用安全性与可维护性。
|
7月前
|
Java 关系型数据库 数据库
深度剖析【Spring】事务:万字详解,彻底掌握传播机制与事务原理
在Java开发中,Spring框架通过事务管理机制,帮我们轻松实现了这种“承诺”。它不仅封装了底层复杂的事务控制逻辑(比如手动开启、提交、回滚事务),还提供了灵活的配置方式,让开发者能专注于业务逻辑,而不用纠结于事务细节。
1011 1
|
10月前
|
人工智能 Java 数据库连接
Spring事务失效场景
本文深入探讨了Spring框架中事务管理可能失效的几种常见场景及解决方案,包括事务方法访问级别不当、方法内部自调用、错误的异常处理、事务管理器或数据源配置错误、数据库不支持事务以及不合理的事务传播行为或隔离级别。通过合理配置和正确使用`@Transactional`注解,开发者可以有效避免这些问题,确保应用的数据一致性和完整性。
838 10
|
9月前
|
Java 关系型数据库 MySQL
【Spring】【事务】初学者直呼学会了的Spring事务入门
本文深入解析了Spring事务的核心概念与使用方法。Spring事务是一种数据库事务管理机制,通过确保操作的原子性、一致性、隔离性和持久性(ACID),维护数据完整性。文章详细讲解了声明式事务(@Transactional注解)和编程式事务(TransactionTemplate、PlatformTransactionManager)的区别与用法,并探讨了事务传播行为(如REQUIRED、REQUIRES_NEW等)及隔离级别(如READ_COMMITTED、REPEATABLE_READ)。
685 1
|
存储 人工智能 Java
【图文详解】基于Spring AI的旅游大师应用开发、多轮对话、文件持久化、拦截器实现
【图文详解】基于Spring AI的旅游大师应用开发、多轮对话、文件持久化、拦截器实现
|
8月前
|
人工智能 安全 Java
Spring Boot 过滤器 拦截器 监听器
本文介绍了Spring Boot中的过滤器、拦截器和监听器的实现与应用。通过Filter接口和FilterRegistrationBean类,开发者可实现对请求和响应的数据过滤;使用HandlerInterceptor接口,可在控制器方法执行前后进行处理;利用各种监听器接口(如ServletRequestListener、HttpSessionListener等),可监听Web应用中的事件并作出响应。文章还提供了多个代码示例,帮助读者理解如何创建和配置这些组件,适用于构建更高效、安全和可控的Spring Boot应用程序。
784 0
|
8月前
|
Java Spring 容器
SpringBoot自动配置的原理是什么?
Spring Boot自动配置核心在于@EnableAutoConfiguration注解,它通过@Import导入配置选择器,加载META-INF/spring.factories中定义的自动配置类。这些类根据@Conditional系列注解判断是否生效。但Spring Boot 3.0后已弃用spring.factories,改用新格式的.imports文件进行配置。
1218 0
|
9月前
|
人工智能 Java 测试技术
Spring Boot 集成 JUnit 单元测试
本文介绍了在Spring Boot中使用JUnit 5进行单元测试的常用方法与技巧,包括添加依赖、编写测试类、使用@SpringBootTest参数、自动装配测试模块(如JSON、MVC、WebFlux、JDBC等),以及@MockBean和@SpyBean的应用。内容实用,适合Java开发者参考学习。
1013 0

热门文章

最新文章