Spring 事务底层源码解析(上)

导读:本篇文章讲解 Spring 事务底层源码解析(上),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

Spring事务管理是基于Spring AOP的,我们在使用Spring事务管理时,需要在配置类上添加@EnableTransactionManagement注解,然后在业务类或方法上添加一个@Transactional注解,就可以开启一个事务,那么Spring是如果通过AOP来处理事务的呢?

一、加载配置类

@EnableTransactionManagement注解会加载TransactionManagementConfigurationSelector配置类,而该类实现了ImportSelector接口,所以在进行配置类解析时,会去调用该类的selectImports()方法,注册新的配置类

@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {

   boolean proxyTargetClass() default false;

   AdviceMode mode() default AdviceMode.PROXY;

   int order() default Ordered.LOWEST_PRECEDENCE;

}

在@EnableTransactionManagement注解中,mode()的属性值为PROXY,所以,在selectImports()方法中又会去注册AutoProxyRegistrar和ProxyTransactionManagementConfiguration这两个配置类

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {

   @Override
   protected String[] selectImports(AdviceMode adviceMode) {
      switch (adviceMode) {
         case PROXY:
            // 默认是PROXY
            return new String[] {AutoProxyRegistrar.class.getName(),
                  ProxyTransactionManagementConfiguration.class.getName()};
         case ASPECTJ:
            // 表示不用动态代理技术,用ASPECTJ技术,比较麻烦了
            return new String[] {determineTransactionAspectClass()};
         default:
            return null;
      }
   }
}

1.1 注册AutoProxyCreator

AutoProxyRegistrar配置解析的时候,由于它实现了ImportBeanDefinitionRegistrar()接口,具有注册BeanDefinition的功能,在解析该类时,会调用registerBeanDefinitions()方法去注册一个InfrastructureAdvisorAutoProxyCreator类的BeanDefinition

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) {
            // 注册InfrastructureAdvisorAutoProxyCreator,才可以Bean进行AOP
            AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
            if ((Boolean) proxyTargetClass) {
               // 设置InfrastructureAdvisorAutoProxyCreator的proxyTargetClass为true
               AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
               return;
            }
         }
      }
   }
}

InfrastructureAdvisorAutoProxyCreator同@Aspect中的AnnotationAwareAspectJAutoProxyCreator一样,都是一个BeanPostProcessor,在Bean实例初始化后中,会去判断当前Bean是否开启了事务,如果开启事务,生成一个代理对象

InfrastructureAdvisorAutoProxyCreator中的isEligibleAdvisorBean()方法用于判断一个Advisor是否是一个事务的Advisor,这一点在下面配置Advisor时会有体现

public class InfrastructureAdvisorAutoProxyCreator extends AbstractAdvisorAutoProxyCreator {

   @Nullable
   private ConfigurableListableBeanFactory beanFactory;


   @Override
   protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
      super.initBeanFactory(beanFactory);
      this.beanFactory = beanFactory;
   }

   @Override
   protected boolean isEligibleAdvisorBean(String beanName) {
      // 判断是不是一个合格的Advisor
      return (this.beanFactory != null && this.beanFactory.containsBeanDefinition(beanName) &&
            this.beanFactory.getBeanDefinition(beanName).getRole() == BeanDefinition.ROLE_INFRASTRUCTURE);
   }

}

1.2 配置Advisor

在ProxyTransactionManagementConfiguration配置类中,生成了三个Bean实例,主要就是去生成一个Advisor的Bean实例

1.2.1 生成Pointcut实例

AnnotationTransactionAttributeSource类就相当于是一个Pointcut,它的isCandidateClass()方法用于判断类上是否有@Transactional注解,但从它的名字可以看出,它并不是一个简单的Pointcut,它还包含了@Transcational注解定义的属性等

@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
   // AnnotationTransactionAttributeSource中构造了一个SpringTransactionAnnotationParser,用来解析类或方法上的@Transactional注解
   return new AnnotationTransactionAttributeSource();
}
public boolean isCandidateClass(Class<?> targetClass) {
    for (TransactionAnnotationParser parser : this.annotationParsers) {
        if (parser.isCandidateClass(targetClass)) {
            return true;
        }
    }
    return false;
}

public boolean isCandidateClass(Class<?> targetClass) {
    return AnnotationUtils.isCandidateClass(targetClass, Transactional.class);
}

1.2.2 生成Advise实例

TransactionInterceptor类相等于是一个Advice,在真正执行业务代码时,会调用它的invoke()方法,在invoke()方法里面才会真正去解决开启事务、事务传播级别、隔离级别等问题

@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;
}

1.2.3 生成Advisor实例

transactionAdvisor()方法其实就是去生成一个Advisor的实例,而一个Advisor包含了Advice和Pointcut两部分,会把上面生成的实例设置进来,然后生成一个Advisor实例

@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
    TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {

    BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
    // BeanFactoryTransactionAttributeSourceAdvisor内部定义了一个Pointcut,Pointcut在匹配时会用到transactionAttributeSource来解析类或方法上是否存在@Transactional
    advisor.setTransactionAttributeSource(transactionAttributeSource);
    advisor.setAdvice(transactionInterceptor);
    if (this.enableTx != null) {
        advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
    }
    return advisor;
}

注:在生成这三个Bean实例时,都通过@Role注解指定了role值为2,与InfrastructureAdvisorAutoProxyCreator中的isEligibleAdvisorBean()方法相匹配

二、生成代理对象

如果开启了Spring事务的支持,也就是注册了InfrastructureAdvisorAutoProxyCreator类的实例,该类是一个BeanPostProcessor,所以在Bean实例初始化后的过程中,会去调用InfrastructureAdvisorAutoProxyCreator的postProcessAfterInitialization()方法,在《Spring AOP源码解析(下)》中,介绍了生成一个代理对象的整体逻辑,不同的只是Advisor,提供了不同的匹配逻辑,在上面配置Advisor时已经介绍了,Spring事务开始时,会注册一个BeanFactoryTransactionAttributeSourceAdvisor类型的Advisor,因为它实现了Advisor接口,所有在筛选的时候,这个Advisor会被拿出来,然后进行匹配,不同只是具体的匹配逻辑

// 找到所有的Advisor
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 进行筛选
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);

下面重点介绍BeanFactoryTransactionAttributeSourceAdvisor中的匹配逻辑

2.1 判断类是否匹配

因为BeanFactoryTransactionAttributeSourceAdvisor同样是实现了PointcutAdvisor接口,所以会进入到canApply()方法中,首先获取Pointcut对象

public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
    if (advisor instanceof IntroductionAdvisor) {
        return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
    }
    else if (advisor instanceof PointcutAdvisor) {
        PointcutAdvisor pca = (PointcutAdvisor) advisor;
        return canApply(pca.getPointcut(), targetClass, hasIntroductions);
    }
    ……
}

BeanFactoryTransactionAttributeSourceAdvisor中定义了一个TransactionAttributeSourcePointcut对象

其中TransactionAttributeSource对象是在配置Advisor时设置的,它实际是一个AnnotationTransactionAttributeSource类的实例

public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {

    @Nullable
    private TransactionAttributeSource transactionAttributeSource;

    private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
        @Override
        @Nullable
        protected TransactionAttributeSource getTransactionAttributeSource() {
            return transactionAttributeSource;
        }
    };
    ……
}

TransactionAttributeSourcePointcut类中定义类匹配的逻辑,就是生成Pointcut实例时提到的isCandidateClass()方法,该方法会判断当前类上是否有@Transactional注解

abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {

    protected TransactionAttributeSourcePointcut() {
        setClassFilter(new TransactionAttributeSourceClassFilter());
    }
	……
    private class TransactionAttributeSourceClassFilter implements ClassFilter {

        @Override
        public boolean matches(Class<?> clazz) {
            if (TransactionalProxy.class.isAssignableFrom(clazz) ||
                TransactionManager.class.isAssignableFrom(clazz) ||
                PersistenceExceptionTranslator.class.isAssignableFrom(clazz)) {
                return false;
            }
            TransactionAttributeSource tas = getTransactionAttributeSource();
            return (tas == null || tas.isCandidateClass(clazz));
        }
    }
}

2.2 判断方法是否匹配

如果类已经匹配了,还需要遍历类中的所有方法,根据方法来判断是否需要进行AOP

TransactionAttributeSourcePointcut中不仅定义了类的匹配逻辑,还定义了方法的匹配逻辑

abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
	……
    @Override
   public boolean matches(Method method, Class<?> targetClass) {
      TransactionAttributeSource tas = getTransactionAttributeSource();
      return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
   }
    ……
}

遍历所有方法,调用matches()方法来进行匹配,而matches()方法中也是调用TransactionAttributeSource对象的getTransactionAttribute()方法来匹配,该方法返回的是一个TransactionAttribute对象,该对象里面是@Transcational注解的配置

调用getTransactionAttribute()时,先从缓存取,缓存没有再调用computeTransactionAttribute()方法来获取方法上@Transcational注解的值,如果返回的TransactionAttribute对象不为空,说明方法上有@Transcational注解,可以进行AOP

不论computeTransactionAttribute()方法返回的对象是否为空,都需要缓存一下,避免下次再次扫描

public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
    // First, see if we have a cached value.
    // 检查缓存里的结果,缓存里存了当前类和方法是否存在Transactional注解
    Object cacheKey = getCacheKey(method, targetClass);
    TransactionAttribute cached = this.attributeCache.get(cacheKey);
    if (cached != null) {
        ……
    }
    else {
        // We need to work it out.
        // 解析,并缓存结果
        TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
        // Put it in the cache.
        if (txAttr == null) {
            this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
        }
        else {
            String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
            if (txAttr instanceof DefaultTransactionAttribute) {
                DefaultTransactionAttribute dta = (DefaultTransactionAttribute) txAttr;
                dta.setDescriptor(methodIdentification);
                dta.resolveAttributeStrings(this.embeddedValueResolver);
            }
            
            this.attributeCache.put(cacheKey, txAttr);
        }
        return txAttr;
    }
}

computeTransactionAttribute()方法中,首先会去判断方法是不是public,也就是说,如果@Transcational定义的方法不是public方法,事务是没法生效的

接着调用findTransactionAttribute()方法去获取方法上@Transcational注解的属性配置

protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
    // Don't allow no-public methods as required.
    if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
        return null;
    }

    // The method may be on an interface, but we need attributes from the target class.
    // If the target class is null, the method will be unchanged.
    Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);

    // First try is the method in the target class.
    // 先检查方法上是否存在@Transactional
    TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
    if (txAttr != null) {
        return txAttr;
    }

    // Second try is the transaction attribute on the target class.
    // 再检查类
    txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
    if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
        return txAttr;
    }
	……

    return null;
}

在parseTransactionAnnotation()方法中,会去获取方法上@Transcational注解的属性值,如果没有注解属性,说明没有该注解

获取到注解的属性值后,通过parseTransactionAnnotation()方法来设置这些属性

protected TransactionAttribute findTransactionAttribute(Method method) {
    return determineTransactionAttribute(method);
}

protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
    for (TransactionAnnotationParser parser : this.annotationParsers) {
        TransactionAttribute attr = parser.parseTransactionAnnotation(element);
        if (attr != null) {
            return attr;
        }
    }
    return null;
}

public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
    AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
        element, Transactional.class, false, false);
    if (attributes != null) {
        return parseTransactionAnnotation(attributes);
    }
    else {
        return null;
    }
}

@Transcational注解的属性值,包括了传播机制、隔离等级、超时、回滚、只读等参数

通过构建一个RuleBasedTransactionAttribute对象来保存@Transactional注解的参数,需要注意的是,rollbackRules这是一个回滚规则的列表,在@Transactional注解中,可以通过rollbackFor、noRollbackFor、rollbackForClassName、noRollbackForClassName来指定哪些异常和错误需要回滚或不会滚

protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
   RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();

   Propagation propagation = attributes.getEnum("propagation");
   rbta.setPropagationBehavior(propagation.value());
   Isolation isolation = attributes.getEnum("isolation");
   rbta.setIsolationLevel(isolation.value());

   rbta.setTimeout(attributes.getNumber("timeout").intValue());
   String timeoutString = attributes.getString("timeoutString");
   Assert.isTrue(!StringUtils.hasText(timeoutString) || rbta.getTimeout() < 0,
         "Specify 'timeout' or 'timeoutString', not both");
   rbta.setTimeoutString(timeoutString);

   rbta.setReadOnly(attributes.getBoolean("readOnly"));
   rbta.setQualifier(attributes.getString("value"));
   rbta.setLabels(Arrays.asList(attributes.getStringArray("label")));

   List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
   for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
      rollbackRules.add(new RollbackRuleAttribute(rbRule));
   }
   for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
      rollbackRules.add(new RollbackRuleAttribute(rbRule));
   }
   for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) {
      rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
   }
   for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {
      rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
   }
   rbta.setRollbackRules(rollbackRules);

   return rbta;
}

匹配之后,如果有符合条件的Advisor,就创建一个代理对象返回

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/112146.html

(0)
Java光头强的头像Java光头强

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!