登录后台

页面导航

本文编写于 957 天前,最后修改于 952 天前,其中某些信息可能已经过时。

@Transactional注解的运行原理

  1. 首先生成事务类的动态代理对象,在执行动态代理事务类的事务方法时,会执行事务拦截器TransactionInterceptor
  2. 接着事务核心组件TransactionAspectSupport开始执行事务方法主流程;

    1. 首先调用Connection.setAutoCommit(false)方法开启事务,本质是基于jdbc连接开启事务方法;
    2. 接着调用目标方法invocation.proceedWithInvocation(),依旧采用ReflectiveMethodInvocation方法调用组件调用目标方法;
    3. 在目标方法执行完成后,判断目标方法是否发生异常;
    4. 如果发生异常,就调用Connection.rollback()方法回滚事务,本质是基于jdbc连接回滚事务;
    5. 如果没有发生异常,就调用Connection.commit()方法提交事务,本质是基于jdbc连接提交事务;

@Transactional事务动态代理对象创建过程

该创建过程和AOP的创建过程一致,只不过事务使用的是BeanFactoryTransactionAttributeSourceAdvisor事务增强advisor来处理事务代理对象;

  1. 从IOC容器中获取bean;
  2. 调用bean后置处理器AbstractAutoProxyCreatorpostProcessBeforeInstantiation()方法;
  3. 判断是否指定targetSource,如果指定了targetSource会跳过bean的实例化和初始化流程,也就是会直接创建AOP代理;
  4. 如果没有指定targetSource,执行正常创建bean的流程,执行bean的初始化,执行initMethod方法;
  5. 调用bean后置处理器AbstractAutoProxyCreatorpostProcessAfterInitialization()方法;
  6. 执行wrapIfNecessary方法包装需要被代理的bean;
  7. 获取所有的增强advisors

    1. 获取xml方式配置的增强advisors
    2. 此处会获取到BeanFactoryTransactionAttributeSourceAdvisor事务增强advisor
    3. 获取@Aspect注解配置的增强advisors,调用BeanFactoryAspectJAdvisorsBuilderbuildAspectJAdvisors方法;
    4. 获取IOC容器中的所有bean,判断是否添加@Aspect注解;
    5. 通过@Aspect注解配置的增强advisors和事务增强的advisor合并在一起将所有的advisors返回;
  8. 调用findAdvisorsThatCanApply方法,从所有增强的advisor中找到与当前bean相匹配的增强Advisors
  9. 遍历当前bean中所有方法依次与advisor的切点表达式进行匹配;

    1. 判断目标类不是java自带的类并且不是Orderd接口类型,如果不满足该条件就不处理当前bean;
    2. 如果满足上面的条件,就获取@Transactional注解中配置的属性(AbstractFallbackTransactionAttributeSource#getTransactionAttribute);
    3. 判断目标方法是否是public方法,如果不是,则不处理当前方法;
    4. 判断目标方法上是否可以获取到@Transactional事务属性,如果可以获取到,就将BeanFactoryTransactionAttributeSourceAdvisor事务增强advisor添加到当前方法的advisors中;
    5. 如果未从方法上获取事务属性,就尝试从类上获取@Transactional事务属性,如果可以获取到,就将BeanFactoryTransactionAttributeSourceAdvisor事务增强advisor添加到当前方法的advisors中;
  10. 创建ProxyFactory对象,并设置相关属性;
  11. 调用createAopProxy方法,获取构造方法默认创建的DefaultAopProxyFactory代理工厂对象,开始选择代理方式并创建代理对象;
详细创建流程可以参考Spring AOP 动态代理的创建过程

@Transactional事务动态代理对象执行过程

  1. 调用事务代理对象的事务方法;
  2. 调用AdvisedSupport#getInterceptorsAndDynamicInterceptionAdvice方法获取拦截器链chain

    1. methodCache缓存中查找是否存在目标方法对应的拦截器链;
    2. 如果没有从methodCache缓存中找到对应的拦截器链,从ProxyFactory中获取目标类对应的类级别增强advisors
    3. 依次遍历所有的增强advsiors是否与目标方法匹配,该过程与@Transactional事务代理对象创建过程中的匹配类似;

      1. 判断目标类不是java自带的类并且不是Orderd接口类型,如果不满足该条件就不处理当前bean;
      2. 如果满足上面的条件,就获取@Transactional注解中配置的属性(AbstractFallbackTransactionAttributeSource#getTransactionAttribute);
      3. 判断目标方法是否是public方法,如果不是,则不处理当前方法;
      4. 判断目标方法上是否可以获取到@Transactional事务属性,如果可以获取到,就获取BeanFactoryTransactionAttributeSourceAdvisor事务增强advisor中的拦截器;
      5. 如果未从方法上获取事务属性,就尝试从类上获取@Transactional事务属性,如果可以获取到,就获取BeanFactoryTransactionAttributeSourceAdvisor事务增强advisor中的拦截器;
      6. 调用AbstractBeanFactoryPointcutAdvisor#getAdvice方法获取增强Advice,该方法会最终调用beanFactory.getBean(this.adviceBeanName, Advice.class)来获取拦截器TransactionInterceptor
      7. 最终将匹配的Advisor收集到interceptorList,并放到methodCache缓存中,以便下一次从缓存获取;
  3. 如果拦截器链chain为空,则通过反射调用目标方法,将结果返回;
  4. 如果拦截器链chain不为空,就将拦截器链chain统一封装为MethodInvocation
  5. 调用ReflectiveMethodInvocation#proceed,执行拦截器链;

    1. 执行拦截器TransactionInterceptor#invoke方法;

      1. 开启事务;
      2. 执行目标方法;
      3. 判断执行目标方法后是否发生异常,如果发生异常,就回滚事务,并抛出该异常;
      4. 如果没有发生异常,就提交事务;
  6. 返回执行结果。

事务失效的常见场景

  1. 事务对象没有被Spring管理;
  2. 事务方法不是public修饰;
  3. 方法内部调用事务方法,这里直接内部调用,没有经过动态代理对象的增强处理,事务增强处理无法执行;
  4. 异常在方法内部捕获,且没有抛出;
  5. rollbackFor属性配置错误;
  6. 数据库引擎不支持事务。