深入理解Spring源码之声明式事务

简介: 深入理解Spring源码之声明式事务
声明式事务环境搭建:
  1、导入相关依赖
          数据源、数据库驱动、Spring-jdbc模块
  2、配置数据源、JdbcTemplate(Spring提供的简化数据库操作的工具)操作数据
  3、给方法上标注 @Transactional 表示当前方法是一个事务方法;
  4、 @EnableTransactionManagement 开启基于注解的事务管理功能;
  5、配置事务管理器来控制事务;
          @Bean
          public PlatformTransactionManager transactionManager()
  原理:
  1)、@EnableTransactionManagement
              利用TransactionManagementConfigurationSelector给容器中会导入组件
              导入两个组件
              AutoProxyRegistrar
              ProxyTransactionManagementConfiguration
  2)、AutoProxyRegistrar:
              给容器中注册一个 InfrastructureAdvisorAutoProxyCreator 组件;
              InfrastructureAdvisorAutoProxyCreator: 
              利用后置处理器机制在对象创建以后,包装对象,返回一个代理对象(增强器),代理对象执
              行方法利用拦截器链进行调用;
  3)、ProxyTransactionManagementConfiguration 做了什么?
              3.1、给容器中注册事务增强器;
                  3.1.1)、事务增强器要用事务注解的信息AnnotationTransactionAttributeSource
                           解析事务注解
                  3.1.2)、事务拦截器:
                           TransactionInterceptor;保存了事务属性信息,事务管理器;他是一个
                      MethodInterceptor;在目标方法执行的时候;执行拦截器链;事务拦截器:
                              3.1.2.1)、先获取事务相关的属性
                              3.1.2.2)、再获取PlatformTransactionManager,如果事先没有添加
                                        指定任何transactionmanger最终会从容器中按照类型获取
                                        一个PlatformTransactionManager;
                              3.1.2.3)、执行目标方法如果异常,获取到事务管理器,利用事务管理
                                         回滚操作;如果正常,利用事务管理器,提交事务

 

 1)、@EnableTransactionManagement

             利用TransactionManagementConfigurationSelector给容器中会导入组件

             导入两个组件

             AutoProxyRegistrar

             ProxyTransactionManagementConfiguration

打来@EnableTransactionManagement的@Import(TransactionManagementConfigurationSelector.class)源码如下:

adviceMode默认是PROXY

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
  /**
   * {@inheritDoc}
   * @return {@link ProxyTransactionManagementConfiguration} or
   * {@code AspectJTransactionManagementConfiguration} for {@code PROXY} and
   * {@code ASPECTJ} values of {@link EnableTransactionManagement#mode()}, respectively
   */
  @Override
  protected String[] selectImports(AdviceMode adviceMode) {
    switch (adviceMode) {
      case PROXY:
        return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
      case ASPECTJ:
        return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
      default:
        return null;
    }
  }
}

一 、AutoProxyRegistrar的解析

 2)、AutoProxyRegistrar:

             给容器中注册一个 InfrastructureAdvisorAutoProxyCreator 组件;

             InfrastructureAdvisorAutoProxyCreator:

             利用后置处理器机制(postProcessAfterInitialization)在对象创建以后,包装对象,返回一个代理对象(增强器),代                理对象执行方法利用拦截器链进行调用;

AutoProxyRegistrar的源码如下:

public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
  private final Log logger = LogFactory.getLog(getClass());
  @Override
  public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    boolean candidateFound = false;
    Set<String> annoTypes = importingClassMetadata.getAnnotationTypes();
    for (String annoType : annoTypes) {
      AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);
      if (candidate == null) {
        continue;
      }
      Object mode = candidate.get("mode");
      Object proxyTargetClass = candidate.get("proxyTargetClass");
      if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
          Boolean.class == proxyTargetClass.getClass()) {
        candidateFound = true;
        if (mode == AdviceMode.PROXY) {
          AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
          if ((Boolean) proxyTargetClass) {
            AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            return;
          }
        }
      }
    }
    if (!candidateFound) {
                      //省略次要代码
    }
  }
}

进入AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);

public abstract class AopConfigUtils {
  public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
    return registerAutoProxyCreatorIfNecessary(registry, null);
  }
  public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
    return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
  }
  public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
    return registerAspectJAutoProxyCreatorIfNecessary(registry, null);
  }
  public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
    return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
  }
  public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
    return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
  }
  public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
    return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
  }
      //忽略非主线代码
}

可以看到最终调用    

public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
        return registerAspectJAutoProxyCreatorIfNecessary(registry, null);
 }

InfrastructureAdvisorAutoProxyCreator 继承自 AbstractAdvisorAutoProxyCreator

顺带提一下AnnotationAwareAspectJAutoProxyCreator是创建AOP代理类里用到的继承AspectJAwareAdvisorAutoProxyCreator

而AspectJAwareAdvisorAutoProxyCreator继承自 AbstractAdvisorAutoProxyCreator

查看AbstractAutoProxyCreator的postProcessAfterInitialization

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  if (bean != null) {
    Object cacheKey = getCacheKey(bean.getClass(), beanName);
    if (!this.earlyProxyReferences.contains(cacheKey)) {
      return wrapIfNecessary(bean, beanName, cacheKey);
    }
  }
  return bean;
}

在 wrapIfNecessary方法的wrapIfNecessary 的 Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);添加条件断点条件为null!=specificInterceptors

可以看到 根据beanName=userService时对应的增强器为

[org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor: advice org.springframework.transaction.interceptor.TransactionInterceptor@3da05287]

ProxyTransactionManagementConfiguration 的解析

 3)、ProxyTransactionManagementConfiguration 做了什么?

             3.1、给容器中注册事务增强器;

                 3.1.1)、事务增强器要用事务注解的信息AnnotationTransactionAttributeSource

                          解析事务注解

                 3.1.2)、事务拦截器:

                          TransactionInterceptor;保存了事务属性信息,事务管理器;他是一个

                     MethodInterceptor;在目标方法执行的时候;执行拦截器链;事务拦截器:

                             3.1.2.1)、先获取事务相关的属性

                             3.1.2.2)、再获取PlatformTransactionManager,如果事先没有添加

                                       指定任何transactionmanger最终会从容器中按照类型获取

                                       一个PlatformTransactionManager;

                             3.1.2.3)、执行目标方法如果异常,获取到事务管理器,利用事务管理

                                        回滚操作;如果正常,利用事务管理器,提交事务总结

 

打开ProxyTransactionManagementConfiguration类可以看到

@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
  @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
  @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
  public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
    BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
    advisor.setTransactionAttributeSource(transactionAttributeSource());
    advisor.setAdvice(transactionInterceptor());
    advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
    return advisor;
  }
  @Bean
  @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
  public TransactionAttributeSource transactionAttributeSource() {
    return new AnnotationTransactionAttributeSource();
  }
  @Bean
  @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
  public TransactionInterceptor transactionInterceptor() {
    TransactionInterceptor interceptor = new TransactionInterceptor();
    interceptor.setTransactionAttributeSource(transactionAttributeSource());
    if (this.txManager != null) {
      interceptor.setTransactionManager(this.txManager);
    }
    return interceptor;
  }
}

TransactionInterceptor 继承自TransactionAspectSupport 主要的事务拦截逻辑在下面这个方法

public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {
  @Override
  public Object invoke(final MethodInvocation invocation) throws Throwable {
    Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
    return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
      @Override
      public Object proceedWithInvocation() throws Throwable {
        return invocation.proceed();
      }
    });
  }
  protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
      throws Throwable {
    // If the transaction attribute is null, the method is non-transactional.
    final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
    final PlatformTransactionManager tm = determineTransactionManager(txAttr);
    final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
    if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
      TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
      Object retVal = null;
      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) {
        // target invocation exception
        completeTransactionAfterThrowing(txInfo, ex);
        throw ex;
      }
      finally {
        cleanupTransactionInfo(txInfo);
      }
      commitTransactionAfterReturning(txInfo);
      return retVal;
    }else {
      try {
        Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,
            new TransactionCallback<Object>() {
              @Override
              public Object doInTransaction(TransactionStatus 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.
                    return new ThrowableHolder(ex);
                  }
                }
                finally {
                  cleanupTransactionInfo(txInfo);
                }
              }
            });
        // Check result: It might indicate a Throwable to rethrow.
        if (result instanceof ThrowableHolder) {
          throw ((ThrowableHolder) result).getThrowable();
        }
        else {
          return result;
        }
      }
      catch (ThrowableHolderException ex) {
        throw ex.getCause();
      }
    }
  }
}

 

总结:通过TransactionInterceptor环绕增强进行事务的增强,即进入目标方法之前开启事务,退出目标方法时提交/回滚事务。开启事务的核心就是从配置的数据源中获取一个数据库连接,关闭自动提交,然后把这个数据库连接绑定到当前线程,供后续使用 TransactionInterceptor保存了事务属性信息,事务管理器;他是一个  MethodInterceptor;在目标方法执行的时候;执行拦截器链;事务拦截器:


目录
相关文章
|
7月前
|
SQL Java 关系型数据库
Spring事务传播机制:7种姿势教你玩转"事务接力赛"
事务传播机制是Spring框架中用于管理事务行为的重要概念,它决定了在方法调用时事务如何传递与执行。通过7种传播行为,开发者可以灵活控制事务边界,适应不同业务场景。例如:REQUIRED默认加入或新建事务,REQUIRES_NEW独立开启新事务,NESTED支持嵌套回滚等。合理使用传播机制不仅能保障数据一致性,还能提升系统性能与健壮性。掌握这“七种人格”,才能在复杂业务中游刃有余。
|
Java Spring
Spring中事务失效的场景
因为Spring事务是基于代理来实现的,所以某个加了@Transactional的⽅法只有是被代理对象调⽤时, 那么这个注解才会⽣效 , 如果使用的是被代理对象调用, 那么@Transactional会失效 同时如果某个⽅法是private的,那么@Transactional也会失效,因为底层cglib是基于⽗⼦类来实现 的,⼦类是不能重载⽗类的private⽅法的,所以⽆法很好的利⽤代理,也会导致@Transactianal失效 如果在业务中对异常进行了捕获处理 , 出现异常后Spring框架无法感知到异常, @Transactional也会失效
|
Java 关系型数据库 数据库
微服务——SpringBoot使用归纳——Spring Boot事务配置管理——常见问题总结
本文总结了Spring Boot中使用事务的常见问题,虽然通过`@Transactional`注解可以轻松实现事务管理,但在实际项目中仍有许多潜在坑点。文章详细分析了三个典型问题:1) 异常未被捕获导致事务未回滚,需明确指定`rollbackFor`属性;2) 异常被try-catch“吃掉”,应避免在事务方法中直接处理异常;3) 事务范围与锁范围不一致引发并发问题,建议调整锁策略以覆盖事务范围。这些问题看似简单,但一旦发生,排查难度较大,因此开发时需格外留意。最后,文章提供了课程源代码下载地址,供读者实践参考。
385 0
|
Java 关系型数据库 数据库
微服务——SpringBoot使用归纳——Spring Boot事务配置管理——Spring Boot 事务配置
本文介绍了 Spring Boot 中的事务配置与使用方法。首先需要导入 MySQL 依赖,Spring Boot 会自动注入 `DataSourceTransactionManager`,无需额外配置即可通过 `@Transactional` 注解实现事务管理。接着通过创建一个用户插入功能的示例,展示了如何在 Service 层手动抛出异常以测试事务回滚机制。测试结果表明,数据库中未新增记录,证明事务已成功回滚。此过程简单高效,适合日常开发需求。
1764 0
|
Java 数据库 微服务
微服务——SpringBoot使用归纳——Spring Boot事务配置管理——事务相关
本文介绍Spring Boot事务配置管理,阐述事务在企业应用开发中的重要性。事务确保数据操作可靠,任一异常均可回滚至初始状态,如转账、购票等场景需全流程执行成功才算完成。同时,事务管理在Spring Boot的service层广泛应用,但根据实际需求也可能存在无需事务的情况,例如独立数据插入操作。
336 0
|
8月前
|
Java 关系型数据库 数据库
深度剖析【Spring】事务:万字详解,彻底掌握传播机制与事务原理
在Java开发中,Spring框架通过事务管理机制,帮我们轻松实现了这种“承诺”。它不仅封装了底层复杂的事务控制逻辑(比如手动开启、提交、回滚事务),还提供了灵活的配置方式,让开发者能专注于业务逻辑,而不用纠结于事务细节。
1123 1
|
前端开发 Java 物联网
智慧班牌源码,采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署
智慧班牌系统是一款基于信息化与物联网技术的校园管理工具,集成电子屏显示、人脸识别及数据交互功能,实现班级信息展示、智能考勤与家校互通。系统采用Java + Spring Boot后端框架,搭配Vue2前端技术,支持SaaS云部署与私有化定制。核心功能涵盖信息发布、考勤管理、教务处理及数据分析,助力校园文化建设与教学优化。其综合性和可扩展性有效打破数据孤岛,提升交互体验并降低管理成本,适用于日常教学、考试管理和应急场景,为智慧校园建设提供全面解决方案。
679 70
|
8月前
|
设计模式 Java 开发者
如何快速上手【Spring AOP】?从动态代理到源码剖析(下篇)
Spring AOP的实现本质上依赖于代理模式这一经典设计模式。代理模式通过引入代理对象作为目标对象的中间层,实现了对目标对象访问的控制与增强,其核心价值在于解耦核心业务逻辑与横切关注点。在框架设计中,这种模式广泛用于实现功能扩展(如远程调用、延迟加载)、行为拦截(如权限校验、异常处理)等场景,为系统提供了更高的灵活性和可维护性。
1134 0
|
11月前
|
人工智能 Java 数据库连接
Spring事务失效场景
本文深入探讨了Spring框架中事务管理可能失效的几种常见场景及解决方案,包括事务方法访问级别不当、方法内部自调用、错误的异常处理、事务管理器或数据源配置错误、数据库不支持事务以及不合理的事务传播行为或隔离级别。通过合理配置和正确使用`@Transactional`注解,开发者可以有效避免这些问题,确保应用的数据一致性和完整性。
1000 10