目录

Spring 事务 @Transactional

@Transactional 是 Spring 中声明式事务管理的注解配置方式,@Transactional 注解可以帮助我们把事务开启、提交或者回滚的操作,通过aop的方式进行管理。

@Transactional 失效场景

  • 修饰方法非 public
  • 在类的内部调用类内部 @Transactional
  • 事务内部捕捉了异常,或者异常非 @Transactional(rollbackFor=RuntimeException.class) 指定异常。

/images/spring/aop/Transactional.png
流程

AOP 实现原理

首先是 @Transactional,作用是定义代理植入点。代理对象创建的通过BeanPostProcessor 的实现类AnnotationAwareAspectJAutoProxyCreator 的postProcessAfterInstantiation 方法来实现个,如果需要进行代理,那么在这个方法就会返回一个代理对象给容器,同时判断植入点也是在这个方法中。

在配置好注解驱动方式的事务管理之后,spring 会在ioc容器创建一个BeanFactoryTransactionAttributeSourceAdvisor 实例,这个实例可以看作是一个切点,在判断一个bean在初始化过程中是否需要创建代理对象,都需要验证一次 BeanFactoryTransactionAttributeSourceAdvisor 是否是适用这个bean的切点。如果是,就需要创建代理对象,并且把 BeanFactoryTransactionAttributeSourceAdvisor 实例注入到代理对象中。

其中 AopUtils#findAdvisorsThatCanApply 中判断切面是否适用当前bean,可以在这个地方断点分析调用堆栈,AopUtils#findAdvisorsThatCanApply 一致调用,最终通过以下代码判断是否适用切点。

  • AbstractFallbackTransactionAttributeSource#computeTransactionAttribute(Method method, Class targetClass) 这里可以根据参数打上条件断点进行调试分析调用栈,targetClass就是目标class

  • 最终SpringTransactionAnnotationParser#parseTransactionAnnotation(java.lang.reflect.AnnotatedElement)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@Override
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {
    //这里就是分析Method是否被@Transactional注解标注,有的话,不用说BeanFactoryTransactionAttributeSourceAdvisor适配当前bean,进行代理,并且注入切点
    //BeanFactoryTransactionAttributeSourceAdvisor
   AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ae, Transactional.class);
   if (attributes != null) {
      return parseTransactionAnnotation(attributes);
   }
   else {
      return null;
   }
}

上面就是判断是否需要根据@Transactional进行代理对象创建的判断过程。@Transactional的作用一个就是标识方法需要被代理,一个就是携带事务管理需要的一些属性信息。

aop最终的代理对象的代理方法是 DynamicAdvisedInterceptor#intercept 跟踪 new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();

CglibMethodInvocation是包装了目标对象的方法调用的所有必须信息,因此,在TransactionInterceptor#invoke里面也是可以调用目标方法的,并且还可以实现类似@Around的逻辑,在目标方法调用前后继续注入一些其他逻辑,比如事务管理逻辑。

TransactionInterceptor 最终事务管理者

TransactionInterceptor#invoke

继续跟踪 TransactionAspectSupport#invokeWithinTransaction,下面的代码中其实就可以看到 TransactionManager 相关事务管理代码。