spring事務管理源碼解析之其餘

本文轉自「天河聊技術」微信公衆號spring

 

說在前面微信

基於註解的spring聲明式事務管理源碼解析已經完畢了,第一篇文章中提到spring事務管理模式有兩種形式一種是proxy,一種是aspectj,基於proxy已經解析完畢了,默認的也是proxy,聲明式事務管理配置一種是基於註解,一種是基於xml配置文件的,最後再補充下基於aspectj這種事務模式和基於xml配置的聲明式事務管理的源碼解析。app

正文ide

基於aspectj的聲明事務管理模式源碼解析ui

找到這個方法org.springframework.transaction.config.AnnotationDrivenBeanDefinitionParser#parsethis

@Override
   @Nullable
   public BeanDefinition parse(Element element, ParserContext parserContext) {
//    註冊事務監聽器工廠
      registerTransactionalEventListenerFactory(parserContext);
//    獲取模式屬性
      String mode = element.getAttribute("mode");
      if ("aspectj".equals(mode)) {
         // mode="aspectj"
         registerTransactionAspect(element, parserContext);
      }
      else {
         // mode="proxy"
         AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
      }
      return null;
   }
if ("aspectj".equals(mode)) {
   // mode="aspectj"
   registerTransactionAspect(element, parserContext);

進入到這個方法spa

org.springframework.transaction.config.AnnotationDrivenBeanDefinitionParser#registerTransactionAspectorm

private void registerTransactionAspect(Element element, ParserContext parserContext) {
      String txAspectBeanName = TransactionManagementConfigUtils.TRANSACTION_ASPECT_BEAN_NAME;
      String txAspectClassName = TransactionManagementConfigUtils.TRANSACTION_ASPECT_CLASS_NAME;
      if (!parserContext.getRegistry().containsBeanDefinition(txAspectBeanName)) {
         RootBeanDefinition def = new RootBeanDefinition();
         def.setBeanClassName(txAspectClassName);
         def.setFactoryMethodName("aspectOf");
//       註冊事務管理器到bean定義中
         registerTransactionManager(element, def);
//       註冊AnnotationTransactionAspect bean定義
         parserContext.registerBeanComponent(new BeanComponentDefinition(def, txAspectBeanName));
      }
   }

進入到這個類xml

org.springframework.transaction.aspectj.AnnotationTransactionAspect對象

public aspect AnnotationTransactionAspect extends AbstractTransactionAspect {

   public AnnotationTransactionAspect() {
//    初始化註解事務資源
      super(new AnnotationTransactionAttributeSource(false));
   }

   /**
    * Matches the execution of any public method in a type with the Transactional將類型中的任何公共方法的執行與事務匹配
    * annotation, or any subtype of a type with the Transactional annotation.註釋,或具備事務註釋的類型的任何子類型。
    */
   private pointcut executionOfAnyPublicMethodInAtTransactionalType() :
      execution(public * ((@Transactional *)+).*(..)) && within(@Transactional *);

   /**
    * Matches the execution of any method with the Transactional annotation.將任何方法的執行與事務註釋匹配。
    */
   private pointcut executionOfTransactionalMethod() :
      execution(@Transactional * *(..));

   /**
    * Definition of pointcut from super aspect - matched join points從超方面匹配的鏈接點定義切入點
    * will have Spring transaction management applied.將應用Spring事務管理。
    */
   protected pointcut transactionalMethodExecution(Object txObject) :
      (executionOfAnyPublicMethodInAtTransactionalType() || executionOfTransactionalMethod() ) && this(txObject);

}

基於aop標籤配置的聲明式事務源碼解析

找到這個方法

org.springframework.transaction.config.TxAdviceBeanDefinitionParser#doParse

@Override
   protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
//    構造事務管理器對象
      builder.addPropertyReference("transactionManager", TxNamespaceHandler.getTransactionManagerName(element));

//    獲取<tx:attributes>子節點
      List<Element> txAttributes = DomUtils.getChildElementsByTagName(element, ATTRIBUTES_ELEMENT);
//    只能有一個<tx:attributes>節點
      if (txAttributes.size() > 1) {
         parserContext.getReaderContext().error(
               "Element <attributes> is allowed at most once inside element <advice>", element);
      }
      else if (txAttributes.size() == 1) {
         // Using attributes source.
         Element attributeSourceElement = txAttributes.get(0);
//       解析<tx:attributes>標籤
         RootBeanDefinition attributeSourceDefinition = parseAttributeSource(attributeSourceElement, parserContext);
         builder.addPropertyValue("transactionAttributeSource", attributeSourceDefinition);
      }
      else {
         // Assume annotations source.
         builder.addPropertyValue("transactionAttributeSource",
               new RootBeanDefinition("org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"));
      }
   }
private RootBeanDefinition parseAttributeSource(Element attrEle, ParserContext parserContext) {
//    獲取<tx:method子節點
      List<Element> methods = DomUtils.getChildElementsByTagName(attrEle, METHOD_ELEMENT);
      ManagedMap<TypedStringValue, RuleBasedTransactionAttribute> transactionAttributeMap =
            new ManagedMap<>(methods.size());
      transactionAttributeMap.setSource(parserContext.extractSource(attrEle));

      for (Element methodEle : methods) {
//       獲取name屬性
         String name = methodEle.getAttribute(METHOD_NAME_ATTRIBUTE);
         TypedStringValue nameHolder = new TypedStringValue(name);
         nameHolder.setSource(parserContext.extractSource(methodEle));

         RuleBasedTransactionAttribute attribute = new RuleBasedTransactionAttribute();
//       獲取事務傳播機制
         String propagation = methodEle.getAttribute(PROPAGATION_ATTRIBUTE);
//       獲取事務隔離級別
         String isolation = methodEle.getAttribute(ISOLATION_ATTRIBUTE);
//       獲取事務超時參數
         String timeout = methodEle.getAttribute(TIMEOUT_ATTRIBUTE);
//       獲取事務只讀屬性
         String readOnly = methodEle.getAttribute(READ_ONLY_ATTRIBUTE);
         if (StringUtils.hasText(propagation)) {
            attribute.setPropagationBehaviorName(RuleBasedTransactionAttribute.PREFIX_PROPAGATION + propagation);
         }
         if (StringUtils.hasText(isolation)) {
            attribute.setIsolationLevelName(RuleBasedTransactionAttribute.PREFIX_ISOLATION + isolation);
         }
         if (StringUtils.hasText(timeout)) {
            try {
               attribute.setTimeout(Integer.parseInt(timeout));
            }
            catch (NumberFormatException ex) {
               parserContext.getReaderContext().error("Timeout must be an integer value: [" + timeout + "]", methodEle);
            }
         }
         if (StringUtils.hasText(readOnly)) {
            attribute.setReadOnly(Boolean.valueOf(methodEle.getAttribute(READ_ONLY_ATTRIBUTE)));
         }

         List<RollbackRuleAttribute> rollbackRules = new LinkedList<>();
         if (methodEle.hasAttribute(ROLLBACK_FOR_ATTRIBUTE)) {
//          獲取事務回滾的異常配置
            String rollbackForValue = methodEle.getAttribute(ROLLBACK_FOR_ATTRIBUTE);
            addRollbackRuleAttributesTo(rollbackRules,rollbackForValue);
         }
         if (methodEle.hasAttribute(NO_ROLLBACK_FOR_ATTRIBUTE)) {
//          獲取不回滾事務的異常類型
            String noRollbackForValue = methodEle.getAttribute(NO_ROLLBACK_FOR_ATTRIBUTE);
            addNoRollbackRuleAttributesTo(rollbackRules,noRollbackForValue);
         }
         attribute.setRollbackRules(rollbackRules);

         transactionAttributeMap.put(nameHolder, attribute);
      }

      RootBeanDefinition attributeSourceDefinition = new RootBeanDefinition(NameMatchTransactionAttributeSource.class);
      attributeSourceDefinition.setSource(parserContext.extractSource(attrEle));
      attributeSourceDefinition.getPropertyValues().add("nameMap", transactionAttributeMap);
      return attributeSourceDefinition;
   }
private void addRollbackRuleAttributesTo(List<RollbackRuleAttribute> rollbackRules, String rollbackForValue) {
//    能夠配置多個異常,用,分開
      String[] exceptionTypeNames = StringUtils.commaDelimitedListToStringArray(rollbackForValue);
      for (String typeName : exceptionTypeNames) {
         rollbackRules.add(new RollbackRuleAttribute(StringUtils.trimWhitespace(typeName)));
      }
   }

   private void addNoRollbackRuleAttributesTo(List<RollbackRuleAttribute> rollbackRules, String noRollbackForValue) {
//    能夠配置多個異常,用,分開
      String[] exceptionTypeNames = StringUtils.commaDelimitedListToStringArray(noRollbackForValue);
      for (String typeName : exceptionTypeNames) {
         rollbackRules.add(new NoRollbackRuleAttribute(StringUtils.trimWhitespace(typeName)));
      }
   }

下面的邏輯都同樣了,都走的是一個事務攔截器攔截事務方法,解析事務屬性,開啓事務進行提交或者回滾。

說到最後

本次解析僅表明我的看法,僅供參考。

相關文章
相關標籤/搜索