4、Spring事务 初始化

万物的起源,AutoConfiuration,这里是TransactionAutoConfiguration,有内部类EnableTransactionManagementConfiguration ,主要作用是引入了注解@EnableTransactionManagement,并确定使用哪种代理方式,jdk或cglib。

@Configuration
@ConditionalOnBean(PlatformTransactionManager.class)
@ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)
public static class EnableTransactionManagementConfiguration {
 
   @Configuration
    // proxyTargetClass = false,使用jdk代理
   @EnableTransactionManagement(proxyTargetClass = false)
   @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = false)
    // 使用jdk代理的条件是,需要在yaml文件中手动指定spring.aop.proxy-target-class=false
   public static class JdkDynamicAutoProxyConfiguration {
 
   }
 
   @Configuration
   @EnableTransactionManagement(proxyTargetClass = true)
    // proxyTargetClass = true,使用cglib代理
   @ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true)
    // 使用cglib代理的条件是,需要在yaml文件中手动指定spring.aop.proxy-target-class=true。但是这里matchIfMissing=true,也就是不配置这条属性也会生效
   public static class CglibAutoProxyConfiguration {
 
   }
 
}

看一下注解@EnableTransactionManagement

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
// 重点是这个
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
 
    // true使用cglib代理,false使用jdk代理
   boolean proxyTargetClass() default false;
 
    // 代理模式,使用Spring自带的编译器,或者是aspecj编译器
    // aop和aspectj没有特别大的关系,只是借用了切点、切面的一些概念。aspectj单独有一套对于面向切面编程的实现
   AdviceMode mode() default AdviceMode.PROXY;
 
    // 有多个advisor的时候定义执行顺序
   int order() default Ordered.LOWEST_PRECEDENCE;
 
}

TransactionManagementConfigurationSelector实现了ImportSelector接口,在初始化时会调用selectImports。
这是TransactionManagementConfigurationSelector的类图

image.png
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
 
   /**
    * Returns {@link ProxyTransactionManagementConfiguration} or
    * {@code AspectJ(Jta)TransactionManagementConfiguration} for {@code PROXY}
    * and {@code ASPECTJ} values of {@link EnableTransactionManagement#mode()},
    * respectively.
    */
   @Override
   protected String[] selectImports(AdviceMode adviceMode) {
        // 默认是PROXY
      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() {
        // 还没找到javax.transaction.Transactional在哪个包下
      return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
            TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
            TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
   }
 
}

这里selectImports又会向容器中注册AutoProxyRegistrar和ProxyTransactionManagementConfiguration。AutoProxyRegistrar的贡献是向容器中注入了InfrastructureAdvisorAutoProxyCreator,InfrastructureAdvisorAutoProxyCreator是service对象生成代理的关键。

后续过程中发现,其实注册的并不是InfrastructureAdvisorAutoProxyCreator
而是AnnotationAwareAspectJAutoProxyCreator
因为优先级AnnotationAwareAspectJAutoProxyCreator高
但是这并不影响对Spring事务的分析
// AopConfigUtils 优先级列表
private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<>(3);

    static {
        // Set up the escalation list...
        // 级别0
        APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
        // 级别1
         APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);      
        // 级别2
        APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
    }

AutoProxyRegistrar实现了ImportBeanDefinitionRegistrar,会调用其registerBeanDefinitions方法

@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
   boolean candidateFound = false;
    // 获取CglibAutoProxyConfiguration上的注解,Configuration、EnableTransactionManagement、ConditionalOnProperty
    // 这里需要的是EnableTransactionManagement
   Set<String> annoTypes = importingClassMetadata.getAnnotationTypes();
   for (String annoType : annoTypes) {
        // 获取注解EnableTransactionManagement的属性
      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;
            // 如果使用Spring的默认增强模式
         if (mode == AdviceMode.PROXY) {
            // 实际是向容器中注册了bean,InfrastructureAdvisorAutoProxyCreator。具体过程省略了。
            AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
            if ((Boolean) proxyTargetClass) {
                // 给InfrastructureAdvisorAutoProxyCreator的beanDefinition增加属性,proxyTargetClass=true
               AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
               return;
            }
         }
        // 这里没有else了,AdviceMode.ASPECTJ是另外一套实现
      }
   }
   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));
   }
}

接着看看,ProxyTransactionManagementConfiguration,里面主要有3个类,

1、BeanFactoryTransactionAttributeSourceAdvisor,定义了切面逻辑TransactionInterceptor和切点TransactionAttributeSourcePointcut(虽然叫切点,但是不是我们常说的切点,只是包含了切点的匹配逻辑)
2、TransactionAttributeSource:包含3个事务注解解析器。SpringTransactionAnnotationParser解析@Transactional,JtaTransactionAnnotationParser解析javax.transaction.Transactional,Ejb3TransactionAnnotationParser解析javax.ejb.TransactionAttribute,
由于我们没有引入jta和ebj相关的jar,所以实际上只有一个解析器:SpringTransactionAnnotationParser
3、TransactionInterceptor:切面逻辑

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

这是TransactionAttributeSourcePointcut的类图


image.png
public interface Pointcut {
 
   ClassFilter getClassFilter();
 
   MethodMatcher getMethodMatcher();
 
   Pointcut TRUE = TruePointcut.INSTANCE;
 
}

TransactionAttributeSourcePointcut实现了MethodMatcher接口和PointCut接口。
PointCut由ClassFilter和MethodMatcher构成,并提供一个TruePointcut的实例,当pointCut为TruePointcut时会忽略所有的匹配条件,
ClassFilter和MethodMatcher分别用于在不同的级别上匹配JointPoint,ClassFilter是类级别,MethodMatcher是方法级别。
TransactionAttributeSourcePointcut中重写了方法的匹配规则matches方法
org.springframework.transaction.interceptor.TransactionAttributeSourcePointcut#matches

@Override
public boolean matches(Method method, Class<?> targetClass) {
    // 目标类不能是TransactionalProxy、PlatformTransactionManager、PersistenceExceptionTranslator或其子类
   if (TransactionalProxy.class.isAssignableFrom(targetClass) ||
         PlatformTransactionManager.class.isAssignableFrom(targetClass) ||
         PersistenceExceptionTranslator.class.isAssignableFrom(targetClass)) {
      return false;
   }
    // 返回的是AnnotationTransactionAttributeSource
   TransactionAttributeSource tas = getTransactionAttributeSource();
   return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}

getTransactionAttributeSource()是抽象方法,在org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor中对其进行了重写,返回的是在ProxyTransactionManagementConfiguration中定义的AnnotationTransactionAttributeSource。
所以最终决定切点匹配的是AnnotationTransactionAttributeSource中的getTransactionAttribute方法返回值是否为空,为空表示方法不匹配,否则表示匹配,并会生成代理。

AnnotationTransactionAttributeSource继承自AbstractFallbackTransactionAttributeSource,getTransactionAttribute在父类AbstractFallbackTransactionAttributeSource中

org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#getTransactionAttribute

@Override
@Nullable
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
    // 代理对象是Object,直接返回空
   if (method.getDeclaringClass() == Object.class) {
      return null;
   }
 
   // First, see if we have a cached value.
    // 根据方法和目标类生成缓存Key,判断是否已经缓存过
   Object cacheKey = getCacheKey(method, targetClass);
   TransactionAttribute cached = this.attributeCache.get(cacheKey);
   if (cached != null) {
      // Value will either be canonical value indicating there is no transaction attribute,
      // or an actual transaction attribute.
      if (cached == NULL_TRANSACTION_ATTRIBUTE) {
         return null;
      }
      else {
         return cached;
      }
   }
   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) txAttr).setDescriptor(methodIdentification);
         }
         if (logger.isTraceEnabled()) {
            logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
         }
         this.attributeCache.put(cacheKey, txAttr);
      }
      return txAttr;
   }
}

org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#computeTransactionAttribute

@Nullable
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
   // Don't allow no-public methods as required.
    // publicMethodsOnly属性默认为true,如果当前方法不是public修饰,返回空
   if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
      return null;
   }
 
    // 如果method是接口中的方法,则获取子类中的方法
   // 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.
   TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
   if (txAttr != null) {
      return txAttr;
   }
 
    // 方法上没有@Transactionl注解,尝试从类上获取
    // Second try is the transaction attribute on the target class.
   txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
   if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
      return txAttr;
   }
 
   if (specificMethod != method) {
      // Fallback is to look at the original method.
      txAttr = findTransactionAttribute(method);
      if (txAttr != null) {
         return txAttr;
      }
      // Last fallback is the class of the original method.
      txAttr = findTransactionAttribute(method.getDeclaringClass());
      if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
         return txAttr;
      }
   }
 
   return null;
}

org.springframework.transaction.annotation.AnnotationTransactionAttributeSource#determineTransactionAttribute

这里this.annotationParsers就是上面提到的事务属性解析器,实际只有一个SpringTransactionAnnotationParser

@Nullable
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
   for (TransactionAnnotationParser annotationParser : this.annotationParsers) {
      TransactionAttribute attr = annotationParser.parseTransactionAnnotation(element);
      if (attr != null) {
         return attr;
      }
   }
   return null;
}
 
 
@Override
@Nullable
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
    // 获取方法上的@Transactionl注解属性
   AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
         element, Transactional.class, false, false);
   if (attributes != null) {
      return parseTransactionAnnotation(attributes);
   }
   else {
      return null;
   }
}

顺便再提一下DataSourceTransactionManagerAutoConfiguration,引入了事务管理器,类型是DataSourceTransactionManager

@Bean
@ConditionalOnMissingBean(PlatformTransactionManager.class)
public DataSourceTransactionManager transactionManager(
      DataSourceProperties properties) {
   DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(
         this.dataSource);
   if (this.transactionManagerCustomizers != null) {
      this.transactionManagerCustomizers.customize(transactionManager);
   }
   return transactionManager;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,185评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,652评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,524评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,339评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,387评论 6 391
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,287评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,130评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,985评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,420评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,617评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,779评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,477评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,088评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,716评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,857评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,876评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,700评论 2 354

推荐阅读更多精彩内容