Spring源码解析系列六:Spring的事务结合Mybatis源码详解

本文深入解析了Spring事务管理的源码,包括@EnableTransactionManagement的处理过程,事务增强的时机和逻辑,以及如何与Mybatis结合。在事务开始时,获取并绑定事务管理器和连接,确保在同一个事务中Mybatis使用同一连接。通过ReflectiveMethodInvocation的proceed方法递归执行,完成事务的提交或回滚。重点分析了REQUIRED传播机制下的事务处理流程,强调了SqlSessionFactory与DataSourceTransactionManager的数据源必须一致以保证事务生效。
摘要由CSDN通过智能技术生成

Spring事务源码详解

简单使用

@Configuration
@EnableTransactionManagement
public class SpringConfig {
   
}

@EnableTransactionManagement解析

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
   

   /**
    * Indicate whether subclass-based (CGLIB) proxies are to be created ({@code true}) as
    * opposed to standard Java interface-based proxies ({@code false}). The default is
    * {@code false}. <strong>Applicable only if {@link #mode()} is set to
    * {@link AdviceMode#PROXY}</strong>.
    * <p>Note that setting this attribute to {@code true} will affect <em>all</em>
    * Spring-managed beans requiring proxying, not just those marked with
    * {@code @Transactional}. For example, other beans marked with Spring's
    * {@code @Async} annotation will be upgraded to subclass proxying at the same
    * time. This approach has no negative impact in practice unless one is explicitly
    * expecting one type of proxy vs another, e.g. in tests.
    */
   boolean proxyTargetClass() default false;

   /**
    * Indicate how transactional advice should be applied.
    * <p><b>The default is {@link AdviceMode#PROXY}.</b>
    * Please note that proxy mode allows for interception of calls through the proxy
    * only. Local calls within the same class cannot get intercepted that way; an
    * {@link Transactional} annotation on such a method within a local call will be
    * ignored since Spring's interceptor does not even kick in for such a runtime
    * scenario. For a more advanced mode of interception, consider switching this to
    * {@link AdviceMode#ASPECTJ}.
    */
   AdviceMode mode() default AdviceMode.PROXY;

   /**
    * Indicate the ordering of the execution of the transaction advisor
    * when multiple advices are applied at a specific joinpoint.
    * <p>The default is {@link Ordered#LOWEST_PRECEDENCE}.
    */
   int order() default Ordered.LOWEST_PRECEDENCE;

}

默认代理模式是AdviceMode.PROXY即JDK动态代理

之后在BeanDefinition加载的时候,调用ImportSelector的selectImports来导入beanName

public final String[] selectImports(AnnotationMetadata importingClassMetadata) {
   
		// 得到 EnableTransactionManagement 类
		Class<?> annType = GenericTypeResolver.resolveTypeArgument(getClass(), AdviceModeImportSelector.class);
		Assert.state(annType != null, "Unresolvable type argument for AdviceModeImportSelector");

		AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
		if (attributes == null) {
   
			throw new IllegalArgumentException(String.format(
					"@%s is not present on importing class '%s' as expected",
					annType.getSimpleName(), importingClassMetadata.getClassName()));
		}
		// 获得 EnableTransactionManagement.mode 的值默认是AdviceMode.PROXY即JDK动态代理
		AdviceMode adviceMode = attributes.getEnum(getAdviceModeAttributeName());
		String[] imports = selectImports(adviceMode);
		if (imports == null) {
   
			throw new IllegalArgumentException("Unknown AdviceMode: " + adviceMode);
		}
		return imports;
	}
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
   

   /**
    * Returns {@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) {
   
         // 默认使用JDK proxy-based advice
         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;
      }
   }

}

返回beanName:AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()

@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());
      if (this.enableTx != null) {
   
         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;
   }

}

在ProxyTransactionManagementConfiguration中利用工厂模式创建BeanFactoryTransactionAttributeSourceAdvisor、TransactionInterceptor、TransactionAttributeSource

小结

使用@EnableTransactionManagement之后,最终会实例化以及初始化三个Bean,BeanFactoryTransactionAttributeSourceAdvisor、TransactionInterceptor、TransactionAttributeSource

使用Advisor进行动态代理增强

增强的时机

增强时机和一致详见Spring的AOP源码详解

只是事务使用findCandidateAdvisors来得到容器中所有的Advisor

分析findCandidateAdvisors的逻辑

protected List<Advisor> findCandidateAdvisors() {
   
   Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
   return this.advisorRetrievalHelper.findAdvisorBeans();
}
public List<Advisor> findAdvisorBeans() {
   
   // Determine list of advisor bean names, if not cached already.
   // 确认advisor的beanName列表,优先从缓存中拿
   String[] advisorNames = this.cachedAdvisorBeanNames;
   if (advisorNames == null) {
   
      // Do not initialize FactoryBeans here: We need to leave all regular beans
      // uninitialized to let the auto-proxy creator apply to them!
      //  如果缓存为空,则获取class类型为Advisor的所有bean名称
      advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
            this.beanFactory, Advisor.class, true, false);
      this.cachedAdvisorBeanNames = advisorNames;
   }
   if (advisorNames.length == 0) {
   
      return new ArrayList<>();
   }

   // 遍历处理advisorNames
   List<Advisor> advisors = new ArrayList<>();
   for (String name : advisorNames) {
   
      if (isEligibleBean(name)) {
   
         // 跳过当前正在创建的advisor
         if (this.beanFactory.isCurrentlyInCreation(name)) {
   
            if (logger.isDebugEnabled()) {
   
               logger.debug("Skipping currently created advisor '" + name + "'");
            }
         }
         else {
   
            try {
   
               // 通过beanName获取对应的bean对象,并添加到advisors
               advisors.add(this.beanFactory.getBean(name, Advisor.class));
            }
            catch (BeanCreationException ex) {
   
               Throwable rootCause = ex.getMostSpecificCause();
               if (rootCause instanceof BeanCurrentlyInCreationException) {
   
                  BeanCreationException bce = (BeanCreationException) rootCause;
                  String bceBeanName = bce.getBeanName();
                  if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
   
                     if (logger.isDebugEnabled()) {
   
                        logger.debug("Skipping advisor '" + name +
                              "' with dependency on currently created bean: " + ex.getMessage());
                     }
                     // Ignore: indicates a reference back to the bean we're trying to advise.
                     // We want to find advisors other than the currently created bean itself.
                     continue;
                  }
               }
               throw ex;
            }
         }
      }
   }
   // 返回符合条件的advisor列表
   return advisors;
}

这里实例化以及初始化了BeanFactoryTransactionAttributeSourceAdvisor

继续分析findAdvisorsThatCanApply从所有候选的Advisor中找出符合条件的,需要遍历初始化成功后类以及类上的方法,判断是否符合条件

protected List<Advisor> findAdvisorsThatCanApply(
      List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
   

   ProxyCreationContext.setCurrentProxiedBeanName(beanName);
   try {
   
      // 从candidateAdvisors中找出符合条件的Advisor
      return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
   }
   finally {
   
      ProxyCreationContext.setCurrentProxiedBeanName(null);
   }
}
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
   
   if (candidateAdvisors.isEmpty()) {
   
      return candidateAdvisors;
   }
   List<Advisor> eligibleAdvisors = new ArrayList<>();
   for (Advisor candidate : candidateAdvisors) {
   
      if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
   
         eligibleAdvisors.add(candidate);
      }
   }
   boolean hasIntroductions = !eligibleAdvisors.isEmpty();
   // 遍历所有的candidateAdvisors
   for (Advisor candidate : candidateAdvisors) {
   
      // 引介增强已经处理,直接跳过
      if (candidate instanceof IntroductionAdvisor) {
   
         // already processed
         continue;
      }
      // 正常增强处理,判断当前bean是否可以应用于当前遍历的增强器
      if (canApply(candidate, clazz, hasIntroductions)) {
   
         eligibleAdvisors.add(candidate);
      }
   }
   return eligibleAdvisors;
}
public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
   
   if (advisor 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值