Spring事务原理之关键注解

Spring事务

Spring事务分为两种:编程式事务和声明式事务

  • 编程式事务:通过编写事务相关的代码来实现对事务开启、提交和回滚的手动控制
  • 声明式事务:一般是通过在方法或者类上面加@Transactional注解来实现

Spring中的事务通过AOP切面成动态代理对象,以此增强对目标方法的调用,增强的功能主要是控制事务的开启、提交和回滚。主要的接口有:

  • TransactionManager:Spring事务管理器实现的标志接口,对标准事务和反应式事务都可用;
  • TransactionStatus:代表事务的状态,事务代码可以使用它来获取事务的状态,也可以在失败的时候,编码式的请求一个回滚;他还包含了SavepointManager接口,用来访问保存点管理信息;注意只有底层事务管理器支持的时候,才能使用保存点管理器。
  • TransactionDefinition:定义符合 Spring 的事务属性的接口,基于类似于 EJB CMT 属性的传播行为定义。
  • SavepointManager:定义一个API,以一种通用的方式来编程式管理事务保存点的接口

Spring动态代理原理

Spring动态代理有两种:CGLIB动态代理和JDK动态代理。

JDK动态代理可以代理接口,不能代理没有实现接口的类;而CGLIB通过字节码技术可以动态生成被代理类的子类,从而可以代理没有实现接口的类;但是不能代理非public和final的方法,因为子类不可见。
请参考:Spring动态代理原理

关键注解

声明式事务主要通过**@EnableTransactionManagement注解声明使用事务,加载配置项;使用@Transactional**注解声明方法或类按事务方式运行;这两个注解的作用可以归纳如下图:

在这里插入图片描述

@EnableTransactionManagement

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

    // 是否创建基于CGLIB的子类代理,默认使用标准JAVA的基于接口的JDK代理
   boolean proxyTargetClass() default false;

    // 事务的advice应该怎么样应用,默认是代理模式
   AdviceMode mode() default AdviceMode.PROXY;

    // 当多个advice在特定的加入点被使用的时候,他可以定义事务advisor的执行顺序
   int order() default Ordered.LOWEST_PRECEDENCE;

}
TransactionManagementConfigurationSelector

该注解上使用@Import导入了TransactionManagementConfigurationSelector相关的配置,TransactionManagementConfigurationSelector类会根据不同的模式(代理模式,切面模式)来加载不同的配置

// 基于导入的配置类中的值选择AbstractTransactionManagementConfiguration的实现
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {

   // 根据EnableTransactionManagement注解中配置的模式返回配置类
   @Override
   protected String[] selectImports(AdviceMode adviceMode) {
      switch (adviceMode) {
         case PROXY: // 代理模式
            return new String[] {AutoProxyRegistrar.class.getName(),
                  ProxyTransactionManagementConfiguration.class.getName()};
         case ASPECTJ: // 切面模式
            return new String[] {determineTransactionAspectClass()};
         default:
            return null;
      }
   }

   private String determineTransactionAspectClass() {
      return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
            TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
            TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
   }

}

代理模式中的AutoProxyRegistrar和ProxyTransactionManagementConfiguration可以创建自动代理、生成BeanFactoryTransactionAttributeSourceAdvisor、TransactionAttributeSource和TransactionInterceptor等事务必要的属性源和拦截器;

AutoProxyRegistrar

AutoProxyRegistrar主要是解析@EnableTransactionManagement注解的属性,根据模式等注册自动代理

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> annTypes = importingClassMetadata.getAnnotationTypes();
      for (String annType : annTypes) {
          // 获取注解的属性
         AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
         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 && logger.isInfoEnabled()) {
         String name = getClass().getSimpleName();
         logger.info(String.format("%s was imported but no annotations were found " +
               "having both 'mode' and 'proxyTargetClass' attributes of type " +
               "AdviceMode and boolean respectively. This means that auto proxy " +
               "creator registration and configuration may not have occurred as " +
               "intended, and components may not be proxied as expected. Check to " +
               "ensure that %s has been @Import'ed on the same class where these " +
               "annotations are declared; otherwise remove the import of %s " +
               "altogether.", name, name, name));
      }
   }

}

AopConfigUtils#registerAutoProxyCreatorIfNecessary会注册org.springframework.aop.config.internalAutoProxyCreator的bean信息

public abstract class AopConfigUtils {
	public static final String AUTO_PROXY_CREATOR_BEAN_NAME = "org.springframework.aop.config.internalAutoProxyCreator";
    
    private static BeanDefinition registerOrEscalateApcAsRequired( Class<?> cls, BeanDefinitionRegistry registry,
                                                                  @Nullable Object source) {

       Assert.notNull(registry, "BeanDefinitionRegistry must not be null");

       if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
          BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
          if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
             int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
             int requiredPriority = findPriorityForClass(cls);
             if (currentPriority < requiredPriority) {
                apcDefinition.setBeanClassName(cls.getName());
             }
          }
          return null;
       }

       RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
       beanDefinition.setSource(source);
       beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
       beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
       registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
       return beanDefinition;
    }
}
ProxyTransactionManagementConfiguration

ProxyTransactionManagementConfiguration是一个配置类,他会注册BeanFactoryTransactionAttributeSourceAdvisor、TransactionAttributeSource、TransactionInterceptor这三个bean。

@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

    // 由一个TransactionAttributeSource驱动的advisor, 用来为事务方法提供事务advice
   @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
   @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
   public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
         TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {

      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(TransactionAttributeSource transactionAttributeSource) {
      TransactionInterceptor interceptor = new TransactionInterceptor();
      interceptor.setTransactionAttributeSource(transactionAttributeSource);
      if (this.txManager != null) {
         interceptor.setTransactionManager(this.txManager);
      }
      return interceptor;
   }

}

@Transactional

该注解可以标记方法或类型,使其以事务的方式运行

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {

   /**
    * 事务管理器别名
    */
   @AliasFor("transactionManager")
   String value() default "";

   /**
    * 事务管理器
    */
   @AliasFor("value")
   String transactionManager() default "";

   /**
    * 事务的传播行为
    */
   Propagation propagation() default Propagation.REQUIRED;

   /**
    * 事务的隔离级别
    */
   Isolation isolation() default Isolation.DEFAULT;

   /**
    * 事务执行的超时时间
    */
   int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;

   /**
    * 是否只读事务
    */
   boolean readOnly() default false;

   /**
    * 事务回滚的异常类型
    */
   Class<? extends Throwable>[] rollbackFor() default {};

   /**
    * 事务回滚的异常类
    */
   String[] rollbackForClassName() default {};

   /**
    *事务不回滚的异常类型
    */
   Class<? extends Throwable>[] noRollbackFor() default {};

   /**
    * 事务不回滚的异常类
    */
   String[] noRollbackForClassName() default {};

}

Spring事务的执行原理请见下一节
Spring事务执行原理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值