浅入浅出代理模式与Spring事务管理

b53a13cef86b93fa3b9c4b796c7119bb.gif

本文回顾了代理模式和Spring事务管理的原理。

前言

最近在开发业务代码的时候,犯了一个事务注解的错误:在同一个类的非事务方法中调用了另一个事务方法,导致事务没有生效,如下所示:

public ConfirmOrderResultVO batchConfirmPurchaseOrders(Long taobaoUserId, List<String> bizOrderIds) throws TCException {
        ………………………………………………………………
        for (String bizOrderId : bizOrderIds) {
            // 推单成功进入successList,否则进入failedList
            if (confirmPurchaseOrder(taobaoUserId, bizOrderId)){
                successList.add(Long.valueOf(bizOrderId));
            }else {
                failedList.add(Long.valueOf(bizOrderId));
            }
        }
        ………………………………………………………………
    }

其中confirmPurchaseOrder()是一个事务方法:

@Transactional
public Boolean confirmPurchaseOrder(Long taobaoUserId, String bizOrderId) throws TCException {
      logger.warn("|ConfirmPurchaseOrder|UserId:"+taobaoUserId+",orderId:"+bizOrderId);
      …………………………
      return ture;
}

这样在直接调用batchConfirmPurchaseOrders()方法时,如果confirmPurchaseOrder()方法发生了异常,是不会回滚的。原理在于Spring的事务管理依靠的动态代理模式,当在同一个类中调用一个非事务方法,是不会生成代理对象的,自然也不会触发事务。借此机会回顾一下代理模式和Spring事务管理的原理。

代理模式

网上讲解代理模式的文章千奇百怪,很多时候看完了也不明白讲的重点是什么。

事实上在生活中我们常常会遇到各种各样的代理模式,例如火车票代售点代理出售火车票,他在“帮忙”出售火车票的同时,收取了额外的手续费,记录了自己店里的流水等。

471a8ea0c41040194448da026b67de29.png

又比如班长代理老师来上交班费,他在“上交班费”的动作之前,还进行了检查班级同学是否到齐、向每一位同学收班费、核对班费金额,最后再上交班费。



f029320ff2f3d8bed25094921621e57c.png



总而言之,代理模式就是代理其他对象,在完成原动作的基础上(前后)做一些额外的自定义的工作

聪明的朋友看到这里一定想到了:那我在一个方法中调用另一个方法不就是代理模式了吗?啊对对对,从功能上来讲是一样的,但是“模式”之所以为“模式”,以我拙见,其本质目的在于形成规范,以减少重复代码的编写。因此如果不能达到减少代码重复这一本质目的,便不能称之为“模式”。

按照代理模式的实现方式,分为两种:静态代理和动态代理。那我们就拿刚刚说过的“写作业”这件事来做例子,讲解一下两种实现方式的区别。

  静态代理

首先定义一个“作业”接口,里面有一个方法“做作业”

public interface Homework {
    void doHomework();
}

小红实现了这个接口。但是小红是一个不爱学习的小学生,又因为师从马掌门成为了学校的扛把子,所以为了不让老师发现,他决定自己随便做做,把剩下的部分交给小弟们来做。

public class XiaoHong implements Homework{
    @Override
    public void doHomework() {
        System.out.println("XiaoHong did homework casually");
    }
}

其中小王、小张两个小弟成绩优异,一个负责数学作业,一个负责英语作业,于是他们两个自告奋勇实现了Homework接口,在代理完成作业的基础上,还不断学习提高自己的能力,并且对作业答案进行了校验。

小王:

public class XiaoWang implements Homework{


    // 持有Homework属性
    private Homework homework;
    // 通过构造函数初始化Homework
    public XiaoWang(Homework homework){
        this.homework=homework;
    }


    //代理实现
    @Override
    public void doHomework() {
        doStudy();
        homework.doHomework();
        System.out.println("XiaoWang helps with MathHomework");
        doCheck();
    }


    // 额外方法 
    private void doCheck() {
        System.out.println("XiaoWang is checking-----------------");
    }
    // 额外方法 
    private void doStudy() {
        System.out.println("XiaoWang is studying---------------");
    }
}

小张:

public class XiaoZhang implements Homework{
    
    // 持有Homework属性
    private Homework homework;
    // 通过构造函数初始化Homework
    public XiaoZhang(Homework homework){
        this.homework=homework;
    }


    //代理实现
    @Override
    public void doHomework() {
        doStudy();
        homework.doHomework();
        System.out.println("XiaoZhang helps with EngHomework");
        doCheck();
    }


    // 额外方法
    private void doCheck() {
        System.out.println("XiaoZhang is checking-----------------");
    }
    // 额外方法
    private void doStudy() {
        System.out.println("XiaoZhang is studying---------------");
    }
}

于是,小红可以放心的把作业交给小王和小张了:

public static void main(String[] args) {
        // 实例化一个目标对象
        XiaoHong xiaoHong = new XiaoHong();
        // 把目标对象通过构造函数传递给代理对象
        XiaoZhang xiaoZhang =new XiaoZhang(xiaoHong);
        XiaoWang xiaoWang =new XiaoWang(xiaoHong);
        // 调用代理对象的方法
        xiaoZhang.doHomework();
        xiaoWang.doHomework();
    }

输出:

XiaoZhang is studying---------------
XiaoHong did homework casually
XiaoZhang helps with EngHomework
XiaoZhang is checking-----------------
  
XiaoWang is studying---------------
XiaoHong did homework casually
XiaoWang helps with MathHomework
XiaoWang is checking-----------------

问题来了,如果老师又布置了一个Book接口和readBook方法,但是readBook前后的动作是一样的(都需要study和check),如何通过代理来实现呢?

一个方案是让小王和小张都实现Book接口和readBook方法,并持有新的Book对象;另一个方案是再找一个小赵实现Book接口和readBook方法。

这样两种方案实际上都能达到效果,但是如果接口和方法增多起来呢?如果让一个代理类实现一堆方法,并持有一堆不同的对象,这个类势必会变得臃肿不堪;如果每一个新的方法都创建一个新的代理类,引用不同的对象,又会造成代码的大量重复。因此,动态代理就出现了。

  动态代理

前文所讲的静态代理之所以为“静态”,是因为每个接口的每个方法,我们都要显式的去实现、创建、调用,所有的操作都是写死的、是静态的。而动态代理的巧妙之处在于,可以在程序的运行期间,动态的生成不同的代理类,来完成相同的工作。也就是说,如果你想实现一个方法,在所有其他方法执行前后做一些额外的相同的动作,例如打印日志、记录方法执行时间等,你就需要动态代理了(是不是想到了什么?)。

事实上所有的动态代理思想都是一致的,而目前最常用的动态代理实现有两种:JDK原生实现和Cglib开源实现。

Spring在5.X之前默认的动态代理实现一直是JDK动态代理。但是从5.X开始,Spring就开始默认使用Cglib来作为动态代理实现。并且SpringBoot从2.X开始也转向了Cglib动态代理实现。

  • JDK实现动态代理

现在有一个牛X的机器人代理,可以帮所有人在完成老师布置的任何任务前后,进行学习和答案的核对,在JDK的动态代理实现中,他是这样编写的:

// 实现InvocationHandler
public class RobotProxy implements InvocationHandler {


    // 持有一个Object类型的目标对象target
    private Object target;
  
    // 通过构造函数实例化目标对象target
    public RobotProxy(Object target) {
        this.target = target;
    }
  
    // 重写invoke方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        doStudy();
        // 执行目标对象的方法
        Object invoke = method.invoke(target, args);
        doCheck();
        return invoke;
    }
    
    // 额外动作
    private void doStudy() {
        System.out.println("Robot is studying------------");
    }
    // 额外动作
    private void doCheck() {
        System.out.println("Robot is checking------------");
    }
}

然后这样调用机器人代理:

public static void main(String[] args) {
  // 实例化一个目标对象
  XiaoHong xiaoHong = new XiaoHong();
  // 传入实现的接口 new Class[]{Homework.class}
  // 以及代理类 new RobotProxy(xiaoHong)
  Homework homework = (Homework)Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Homework.class}, new RobotProxy(xiaoHong));
  homework.doHomework();
}

输出:

Robot is studying------------
XiaoHong did homework casually
Robot is checking------------

可以看到,JDK实现动态代理必须要依赖接口,只有实现了接口的目标类才可以被代理,而Cglib动态代理就可以消除接口的限制。

  • Cglib实现动态代理

创建一个升级版的机器人RovotV2代理类:

// 实现MethodInterceptor方法(要引入cglib包)
public class RobotV2Proxy implements MethodInterceptor {
  
    // 重写intercept方法
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        doStudy();
        Object invoke = methodProxy.invokeSuper(o, objects);
        doCheck();
        return invoke;
    }


    // 额外动作
    private void doStudy() {
        System.out.println("RobotV2 is studying------------");
    }
    // 额外动作
    private void doCheck() {
        System.out.println("RobotV2 is checking------------");
    }
}

调用方式:

public static void main(String[] args) {
    // 创建增强类
    Enhancer enhancer = new Enhancer();
    // 设置父类
    enhancer.setSuperclass(XiaoHong.class);
    // 设置回调
    enhancer.setCallback(new RobotV2Proxy());
    // 创建目标对象
    XiaoHong xiaoHong = (XiaoHong)enhancer.create();
    // 调用目标方法
    xiaoHong.doHomework();
}

输出:

RobotV2 is studying------------
XiaoHong did homework casually
RobotV2 is checking------------

Cglib动态代理相比于JDK代理实现有几个优势:

  1. 基于字节码,生成真实对象的子类。

  2. 运行效率高于JDK代理

  3. 不需要实现接口

可以看到,动态代理只需要一个代理类,就可以代理所有需要同一种处理(如上文所述的study()、check())的类和方法,这就是动态代理与静态代理最大的区别。

Spring事务管理

OK,了解到了代理模式的好处之后,就可以自然而然的想到Spring事务管理的基本原理了。无非是借助动态代理,做一些额外的操作:在真正的方法执行之前开启事务,在方法顺利执行完成之后提交事务,如果方法执行过程中发生异常,要执行回滚操作。

一般有两种方法使用Spring的事务管理,一种是利用注解,一种是手动编程。本文因为使用的是注解型的事务管理,因此只对注解型事务的使用和原理进行探究,以找到事务没有生效的原因。

  注解型事务
  • 注解型事务使用

注解型事务的使用非常简单,只需要在需要事务管理的类或方法上加上@Transactional(rollbackFor = Exception.class),其中rollbackFor指定的是遇到什么情况下执行回滚。

当然这个注解还有传播级别、隔离级别等我们背过的八股文属性,就不一一展开了。

  • 事务执行原理

PlatformTransactionManager

我们知道,事务是针对数据库而言的。事实上,Spring并不直接管理事务,他只是提供了一套统一的框架和接口,具体由不同的、真正与数据库打交道的持久层框架来实现,如Hibernate、Ibatis、Mybatis等,这个统一的接口是PlatformTransactionManager,它提供了三个核心方法:获取事务(getTransaction)、提交事务(commit)、回滚事务(rollback),同时Spring提供了一个统一的抽象实现类AbstractPlatformTransactionManager,这是其他持久层框架事务实现类的共同父类。

public interface PlatformTransactionManager extends TransactionManager {
    
  /**
  * 获取事务
  /*
  TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;
  
  /**
  * 提交事务
  /*
  void commit(TransactionStatus status) throws TransactionException;


  /**
  * 回滚事务
  /*
  void rollback(TransactionStatus status) throws TransactionException;
}

先来看getTransaction方法:

@Override
  public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
      throws TransactionException {


    // 获取事务定义(该类保存了当前事务的相关属性,例如传播规则、隔离规则等)
    TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
    // 获取真正的事务(doGetTransaction方法由具体的持久层框架实现)
    Object transaction = doGetTransaction();
    boolean debugEnabled = logger.isDebugEnabled();
    
    // 如果已经存在事务,则根据传播规则执行相应的处理
    if (isExistingTransaction(transaction)) {
      return handleExistingTransaction(def, transaction, debugEnabled);
    }


    // 检查当前事务的超时时间
    if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
      throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
    }


    // 如果当前不存在事务,检查传播级别和隔离级别,开始执行事务 startTransaction()
    if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
      throw new IllegalTransactionStateException(
          "No existing transaction found for transaction marked with propagation 'mandatory'");
    }
    else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
        def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
        def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
      SuspendedResourcesHolder suspendedResources = suspend(null);
      if (debugEnabled) {
        logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
      }
      try {
        return startTransaction(def, transaction, debugEnabled, suspendedResources);
      }
      catch (RuntimeException | Error ex) {
        resume(null, suspendedResources);
        throw ex;
      }
    }
    else {
      // Create "empty" transaction: no actual transaction, but potentially synchronization.
      if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
        logger.warn("Custom isolation level specified but no actual transaction initiated; " +
            "isolation level will effectively be ignored: " + def);
      }
      boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
      return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
    }
  }

小结:getTransaction方法就是根据具体的传播行为返回一个当前存在的事务或者一个新的事务对象



再来看提交事务方法commit:

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()) {
      if (defStatus.isDebug()) {
        logger.debug("Transactional code has requested rollback");
      }
      processRollback(defStatus, false);
      return;
    }
    // 如果全局事务设置了回滚标识,则进行回滚操作(也就是事务嵌套的场景)
    if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
      if (defStatus.isDebug()) {
        logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
      }
      processRollback(defStatus, true);
      return;
    }
    // 提交事务
    processCommit(defStatus);
  }

小结:commit方法就是根据事务状态提交事务,如果事务被标记为“回滚”态,则进行回滚操作



最后来看rollback方法:

public final void rollback(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;
    processRollback(defStatus, false);
  }

processRollback方法:

private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
    try {
      boolean unexpectedRollback = unexpected;


      try {
        triggerBeforeCompletion(status);
        // 如果当前事务存在保存点,则回滚到保存点的状态
        if (status.hasSavepoint()) {
          if (status.isDebug()) {
            logger.debug("Rolling back transaction to savepoint");
          }
          status.rollbackToHeldSavepoint();
        }
        // 如果是新的事务,则执行doRollback方法
        else if (status.isNewTransaction()) {
          if (status.isDebug()) {
            logger.debug("Initiating transaction rollback");
          }
          doRollback(status);
        }
        else {
          // 如果有嵌套事务,则执行doSetRollbackOnly方法
          if (status.hasTransaction()) {
            if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
              if (status.isDebug()) {
                logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
              }
              doSetRollbackOnly(status);
            }
            else {
              if (status.isDebug()) {
                logger.debug("Participating transaction failed - letting transaction originator decide on rollback");
              }
            }
          }
          else {
            logger.debug("Should roll back transaction but cannot - no transaction available");
          }
          // Unexpected rollback only matters here if we're asked to fail early
          if (!isFailEarlyOnGlobalRollbackOnly()) {
            unexpectedRollback = false;
          }
        }
      }
      catch (RuntimeException | Error ex) {
        triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
        throw ex;
      }


      triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);


      // Raise UnexpectedRollbackException if we had a global rollback-only marker
      // 发生了不期望的回滚异常
      if (unexpectedRollback) {
        throw new UnexpectedRollbackException(
            "Transaction rolled back because it has been marked as rollback-only");
      }
    }
    finally {
      cleanupAfterCompletion(status);
    }
  }

这里我们看到了一句熟悉的话"Transaction rolled back because it has been marked as rollback-only",相信一定有朋友在使用事务中看到过这个异常(不要犟),一般存在在这种场景下:A类的事务方法中调用了B类的事务方法,B方法发生了异常,但是在A类的try-catch模块中捕获了这个异常并正常执行。

这个异常发生的原因是:Spring默认的事务传播级别是propagation.REQUIRED,即如果有没有事务则新启一个事务,如果已经存在事务则加入这个事务。B方法发生了异常,给当前事务打上了rollbackOnly标记,但是被A捕获到了并正常执行,由于只有一个事务,等到A方法要提交这一个事务的时候,没有发现异常但是发现事务被打上了rollbackOnly,只能回滚并抛出一个unexpectedRollback异常。

  • DynamicAdvisedInterceptor

现在,我们已经明确了事务的执行过程。那既然我们是使用注解来进行事务管理的,有了注解,就一定有注解的处理器,这时候就要搬出Spring的核心法宝——AOP。Spring就是通过切面来获取所有的Spring注解、解析注解并处理注解下的类、方法等。而AOP的核心是动态代理,我们找到AOP包下的Cglib动态代理类CglibAopProxy,其中有内部静态类DynamicAdvisedInterceptor

private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {


    private final AdvisedSupport advised;


    public DynamicAdvisedInterceptor(AdvisedSupport advised) {
      this.advised = advised;
    }


    @Override
    @Nullable
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
      Object oldProxy = null;
      boolean setProxyContext = false;
      Object target = null;
      TargetSource targetSource = this.advised.getTargetSource();
      try {
        if (this.advised.exposeProxy) {
          // Make invocation available if necessary.
          oldProxy = AopContext.setCurrentProxy(proxy);
          setProxyContext = true;
        }
        // Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
        target = targetSource.getTarget();
        Class<?> targetClass = (target != null ? target.getClass() : null);
        List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
        Object retVal;
        // Check whether we only have one InvokerInterceptor: that is,
        // no real advice, but just reflective invocation of the target.
        if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
          // We can skip creating a MethodInvocation: just invoke the target directly.
          // Note that the final invoker must be an InvokerInterceptor, so we know
          // it does nothing but a reflective operation on the target, and no hot
          // swapping or fancy proxying.
          Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
          retVal = methodProxy.invoke(target, argsToUse);
        }
        else {
          // We need to create a method invocation...
          retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
        }
        retVal = processReturnType(proxy, target, method, retVal);
        return retVal;
      }
      finally {
        if (target != null && !targetSource.isStatic()) {
          targetSource.releaseTarget(target);
        }
        if (setProxyContext) {
          // Restore old proxy.
          AopContext.setCurrentProxy(oldProxy);
        }
      }
    }

其中有两个核心方法:

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();

第一个方法是获取拦截链,第二个方法是创建拦截链的Cglib代理对象来执行。对于SpringAOP来讲,凡是需要AOP增强的地方都会进入到这个方法,加载一系列的拦截器,按照责任链模式执行。所有拦截器都会实现MethodInterceptor接口,和invoke方法。

  • TransactionInterceptor

我们顺藤摸瓜,找到了与事务相关的拦截器TransactionInterceptor,它实现了AOP包下的MethodInterceptor接口,和一个核心的调用方法invoke:

public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
    @Nullable
    public Object invoke(final MethodInvocation invocation) throws Throwable {
        // 获取目标类
        Class<?> targetClass = invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null;
        // 执行事务方法
        return this.invokeWithinTransaction(invocation.getMethod(), targetClass, new CoroutinesInvocationCallback() {
            @Nullable
            public Object proceedWithInvocation() throws Throwable {
                return invocation.proceed();
            }


            public Object getTarget() {
                return invocation.getThis();
            }


            public Object[] getArguments() {
                return invocation.getArguments();
            }
        });
    }
}
invokeWithinTransaction

进入invokeWithinTransaction方法:

@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
      final InvocationCallback invocation) throws Throwable {


   // If the transaction attribute is null, the method is non-transactional.
   TransactionAttributeSource tas = getTransactionAttributeSource();
   // 获取事务属性类TransactionAttribute
   final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
   // 根据事务属性选择合适的事务管理器(如PlatformTransactionManager)
   final TransactionManager tm = determineTransactionManager(txAttr);
   ………………………………………………………………………………
}
getTransactionAttribute

再看getTransactionAttribute方法:

public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
   if (method.getDeclaringClass() == Object.class) {
      return null;
   }


   // 从缓存中获取TransactionAttribute
   Object cacheKey = getCacheKey(method, targetClass);
   TransactionAttribute cached = this.attributeCache.get(cacheKey);
   if (cached != null) {
      // Value will either be canonical value indicating there is no transaction attribute,
      // or an actual transaction attribute.
      if (cached == NULL_TRANSACTION_ATTRIBUTE) {
         return null;
      }
      else {
         return cached;
      }
   }
   else {
      // 如果缓存中没有TransactionAttribute,则构建一个新的TransactionAttribute
      TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
      // Put it in the cache.
      if (txAttr == null) {
         this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
      }
     ………………………………………………………………………………
}
computeTransactionAttribute

再进入到computeTransactionAttribute方法中:

protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
    // 校验当前注解的方法是否是public的(也就是@Transactional注解的方法必须是public的)
    if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
      return null;
    }


    // 获取真实目标对象的方法(获取代理对象真正代理的目标对象的执行方法)
    Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);


    // 从目标对象的方法中获取事务属性(其实就是在找注解,先找方法上有没有注解)
    TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
    if (txAttr != null) {
      return txAttr;
    }


    // 从目标对象的类中获取事务属性(再找类上有没有注解)
    txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
    if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
      return txAttr;
    }


    if (specificMethod != method) {
      // Fallback is to look at the original method.
      txAttr = findTransactionAttribute(method);
      if (txAttr != null) {
        return txAttr;
      }
      // Last fallback is the class of the original method.
      txAttr = findTransactionAttribute(method.getDeclaringClass());
      if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
        return txAttr;
      }
    }


    return null;
  }
invokeWithinTransaction

拿到事务管理器后,再回到invokeWithinTransaction方法,我们看到一些核心代码:

PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
    final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);


    if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
      // Standard transaction demarcation with getTransaction and commit/rollback calls.
      TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);


      Object retVal;
      try {
        // 动态代理调用目标对象本身的数据库操作
        // This is an around advice: Invoke the next interceptor in the chain.
        // This will normally result in a target object being invoked.
        retVal = invocation.proceedWithInvocation();
      }
      catch (Throwable ex) {
        // 如果发生异常要进行回滚(内部是获取相应的TransactionManager,执行rollback方法)
        // target invocation exception
        completeTransactionAfterThrowing(txInfo, ex);
        throw ex;
      }
      finally {
        // 释放事务资源
        cleanupTransactionInfo(txInfo);
      }


      if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
        // Set rollback-only in case of Vavr failure matching our rollback rules...
        TransactionStatus status = txInfo.getTransactionStatus();
        if (status != null && txAttr != null) {
          retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
        }
      }
      // 提交事务(内部是获取相应的TransactionManager,执行commit方法)
      commitTransactionAfterReturning(txInfo);
      return retVal;
    }

总结

Spring通过AOP,在执行具有@Transactional注解的方法时,会根据目标类生成一个代理对象,在目标方法执行之前获取事务并开启事务,在目标方法执行之后提交事务或者回滚事务。当执行一个类中的普通方法时,Spring没有生成代理对象,即使这个方法内部调用了同类其他的事务方法,也就无法参与事务管理了。



团队介绍

天猫优品是天猫面向县域下沉市场的新零售品牌,依托集团大中台,围绕品牌-天猫优品平台-门店-消费者四个商业角色,构建了SBbc全链路新零售解决方案。自2020年6月回归天猫行业后,支撑了天猫优品直营业务的持续增长,同时沉淀了消电行业门店新零售数字化解决方案。

✿  拓展阅读

199bb5de15386109e26bacf0075280de.png

3d58f9d215721bae34ca228f53ee2018.png

作者|结森

编辑|橙子君

88bd9f30f4dfce8f31d12f8f5df20e48.png

c7815677605728cc4deb45ed5ec38ba6.png

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值