Spring源码情操陶冶-tx:advice解析器

承接Spring源码情操陶冶-自定义节点的解析。本节关于事务进行简单的解析

spring配置文件样例

简单的事务配置,对save/delete开头的方法加事务,get/find开头的设置为不加事务只读模式

<tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="save*" propagation="REQUIRED"/>
            <tx:method name="delete*" propagation="REQUIRED"/>
            <tx:method name="get*" read-only="true"/>
            <tx:method name="find*" read-only="true"/>
        </tx:attributes>
</tx:advice>

TxAdviceBeanDefinitionParser解析器

tx:advice节点对应的解析器为TxAdviceBeanDefinitionParser,下面针对该解析器作下详细的解读

实例化对象

直接看复写的getBeanClass()方法

    @Override
    protected Class<?> getBeanClass(Element element) {
        return TransactionInterceptor.class;
    }

TxAdviceBeanDefinitionParser解析器最终解析tx:advice节点为TransactionInterceptor对象

通用的属性集合

    private static final String METHOD_ELEMENT = "method";

    private static final String METHOD_NAME_ATTRIBUTE = "name";

    private static final String ATTRIBUTES_ELEMENT = "attributes";

    private static final String TIMEOUT_ATTRIBUTE = "timeout";

    private static final String READ_ONLY_ATTRIBUTE = "read-only";

    private static final String PROPAGATION_ATTRIBUTE = "propagation";

    private static final String ISOLATION_ATTRIBUTE = "isolation";

    private static final String ROLLBACK_FOR_ATTRIBUTE = "rollback-for";

    private static final String NO_ROLLBACK_FOR_ATTRIBUTE = "no-rollback-for";

针对上述的属性,我们可以看下其中的具体解析

doParse()-解析tx:advice节点

源码端上

    @Override
    protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
        // 解析transaction-manager属性对应的bean ref名,默认名为transactionManager
        builder.addPropertyReference("transactionManager", TxNamespaceHandler.getTransactionManagerName(element));

        // 解析子节点tx:attributes
        List<Element> txAttributes = DomUtils.getChildElementsByTagName(element, ATTRIBUTES_ELEMENT);
        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:attribute集合
            RootBeanDefinition attributeSourceDefinition = parseAttributeSource(attributeSourceElement, parserContext);
            builder.addPropertyValue("transactionAttributeSource", attributeSourceDefinition);
        }
        else {
            // 注册解析器用于解析注解@Transactional
            builder.addPropertyValue("transactionAttributeSource",
                    new RootBeanDefinition("org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"));
        }
    }

对于@Transactional方式的解析我们不在此处展开,我们先看下通用的parseAttributeSource()方法解析tx:attribute集合,其会被包装为NameMatchTransactionAttributeSource.class对象。源码如下

private RootBeanDefinition parseAttributeSource(Element attrEle, ParserContext parserContext) {
        // 解析tx:method节点
        List<Element> methods = DomUtils.getChildElementsByTagName(attrEle, METHOD_ELEMENT);
        ManagedMap<TypedStringValue, RuleBasedTransactionAttribute> transactionAttributeMap =
            new ManagedMap<TypedStringValue, RuleBasedTransactionAttribute>(methods.size());
        transactionAttributeMap.setSource(parserContext.extractSource(attrEle));

        //
        for (Element methodEle : methods) {
            // 解析name属性,其可符合ant-style模式.包装成TypedStringValue对象
            String name = methodEle.getAttribute(METHOD_NAME_ATTRIBUTE);
            TypedStringValue nameHolder = new TypedStringValue(name);
            nameHolder.setSource(parserContext.extractSource(methodEle));

            // 解析propagation、isolation、timeout、read-only属性
            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)));
            }

            // 解析rollback-for、no-rollback-for属性
            List<RollbackRuleAttribute> rollbackRules = new LinkedList<RollbackRuleAttribute>();
            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);
        }

        // 最后包装成NameMatchTransactionAttributeSource对象,存放上述的配置
        RootBeanDefinition attributeSourceDefinition = new RootBeanDefinition(NameMatchTransactionAttributeSource.class);
        attributeSourceDefinition.setSource(parserContext.extractSource(attrEle));
        attributeSourceDefinition.getPropertyValues().add("nameMap", transactionAttributeMap);
        return attributeSourceDefinition;
    }

代码很简单,都是解析属性的,不过还是对上述的一些配置作下白话的总结


  • name 支持ant-style语法,即匹配对应的方法,比如save*,匹配saveUser()/save()等方法
  • propagation 事务传播方式,对应spring的TransactionDefinition接口类常量
    • required 对应PROPAGATION_REQUIRED,对当前的方法判断如果不存在事务,则创建事务。默认配置
    • required_new 对应PROPAGATION_REQUIRED_NEW,对当前方法判断如果存在事务,则创建新事务,待方法执行完毕后恢复事务;反之创建新事务,让方法运行在新事务环境下。即当前方法将运行在独立的新事务下
    • supports 对应PROPAGATION_SUPPORTS,对当前方法判断如果存在事务,则加入该事务;反之则让方法处于非事务状态执行
    • not_spported 对应PROPAGATION_NOT_SUPPORTED,对当前方法判断如果存在事务,则挂起该事务,等方法执行完毕后,再恢复事务。即当前方法不需要事务支持
    • mandatory 对应PROPAGATION_MANDATORY,对当前方法判断如果存在事务,则加入该事务;反之不能新建事务,且抛出异常。即必须处于事务下运行
    • never 对应PROPAGATION_NEVER,对当前方法判断如果存在事务,则抛异常;反之正常运行。即必须在非事务下运行
    • nested 对应PROPAGATION_NESTED,可嵌入式的事务。
  • isolation 事务隔离级别,对应spring的TransactionDefinition接口类常量
    • default 对应ISOLATION_DEFAULT,不作隔离要求,可能会导致dirty read/unrepeatable read/phantom read
    • read_uncommitted 对应JDBC Connection的TRANSACTION_READ_UNCOMMITTED ,可能会导致dirty read/unrepeatable read/phantom read
    • read_committed 对应JDBC Connection的TRANSACTION_READ_COMMITTED,可能会导致unrepeatable read/phantom read
    • reaptable_read 对应JDBC Connection的TRANSACTION_REPEATABLE_READ,可能会导致phantom read
    • serializable 对应JDBC Connection的TRANSACTION_SERIALIZABLE,最安全但最耗性能
      其中关于脏读、不可重复读、幻读的概念见引文https://blog.csdn.net/wang379275614/article/details/24818397。另附言博主对不可重复读、幻读的理解

      两者均是在同一事务中会出现的情况,执行的条件均一样。但不可重复读关心返回的数据是否一致,而幻读关心返回的数据条数是否一致

  • timeout 超时参数,单位为s。其只应用于事务传播方式为Required/Required_new,默认为-1
  • read-only 是否配置事务只读,默认为false
  • rollback-for 异常回滚策略配置,即出现何种异常进行回滚,可配置多个异常,支持,分隔。注意此处的配置的异常名也符合ant-style模式
  • no-rollback-for 异常不回滚策略配置,即出现何种异常不进行回滚,可配置多个异常,支持,分隔。注意此处的配置的异常名也符合ant-style模式


Spring源码情操陶冶-tx:advice解析器

原文地址:https://www.cnblogs.com/question-sky/p/9056649.html

时间: 2024-10-27 07:14:02

Spring源码情操陶冶-tx:advice解析器的相关文章

Spring源码情操陶冶#task:scheduled-tasks解析器

承接前文Spring源码情操陶冶#task:executor解析器,在前文基础上解析我们常用的spring中的定时任务的节点配置.备注:此文建立在spring的4.2.3.RELEASE版本 附例 Spring中的定时任务基本配置样例如下 <!--create schedule thread pool--> <task:scheduler id="baseScheduler" pool-size="5"></task:scheduler

spring源码(3)之解析配置文件的过程

spring源码之解析配置文件过程 上篇博文,我们探讨了spring获取配置文件applicationContext.xml的document对象.回想struct2解析struct*.xml,当struct2获取struct*.xml文件的document对象之后,就会循环遍历这个document,然把不同的标签的信息封装到不同的对象中,如<package>标签封装到packageConfig对象,<action>标签封装到actionConfig对象等等.那么spring在获取

spring beans源码解读之--bean definiton解析器

spring提供了有两种方式的bean definition解析器:PropertiesBeanDefinitionReader和XmLBeanDefinitionReader即属性文件格式的bean definition解析器和xml文件格式的bean definition解析器. 我们先从简单的PropertiesBeanDefinitionReader开始深入挖掘. 1. PropertiesBeanDefinitionReader 属性文件bean definition解析器 1.1  

【spring源码分析】--Bean的解析与注册

接着上一节继续分析,DefaultBeanDefinitionDocumentReader的parseBeanDefinitions方法: protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); for (int i =

[原创]spring源码解析-- 定义Advice接口的作用和意图

Spring在包org.aopalliance.aop下定义了Advice接口,该接口没有任何方法和属性: public interface Advice { } 那么Spring定义该接口的意图是什么呢?该接口的作用是什么呢?针对这些问题,我会不断通过研究Spring源码,持续更新最新的发现.

Spring 源码解析之HandlerAdapter源码解析(二)

Spring 源码解析之HandlerAdapter源码解析(二) 前言 看这篇之前需要有Spring 源码解析之HandlerMapping源码解析(一)这篇的基础,这篇主要是把请求流程中的调用controller流程单独拿出来了 解决上篇文章遗留的问题 getHandler(processedRequest) 这个方法是如何查找到对应处理的HandlerExecutionChain和HandlerMapping的,比如说静态资源的处理和请求的处理肯定是不同的HandlerMapping ge

spring源码剖析(二)Spring默认标签解析及注册实现

在使用spring的时候,我也经常会使用到bean标签,beans标签,import标签,aop标签等. 下面主要为读者介绍spring的默认的自带标签的解析流程. 验证模式(DTD&XSD) dtd基本已被淘汰,现在spring的验证模式基本都是采用xsd文件作为xml文档的验证模式,通过xsd文件可以检查该xml是否符合规范,是否有效.在使用xsd文件对xml文档进行校验的时候,除了要名称空间外(xmlns="http://www.springframework.org/schema

Spring源码深度解析第一天

其实第一天已经过去了,今天是第二天.iteye刚注册的小号就被封了.不论是它的失误还是他的失误总之我跟iteye是没有缘分了. 昨天基本没有进展.所以从今天开始说了.下面流水账开始了. <Spring源码深度解析>这本书没有pdf完整版是让我很失望的.如果有完整版即使看完了我也会选择买一本实体如果有用的话. 书中说从github下载源码.发现github没有想象中的简单易懂.还需要记忆很多命令才能玩得转.从github上获得了Spring源码后需要使用Gradle来编译成eclipse项目.g

SPRING技术内幕,Spring源码深度解析

 SPRING技术内幕,Spring源码深度解析 SPRING技术内幕:深入解析SPRING架构与设计原理(第2版)[带书签].pdf: http://www.t00y.com/file/78131650 Spring源码深度解析 [郝佳编著] sample.pdf: http://www.t00y.com/file/78131634 [jingshuishenliu.400gb.com]Spring Data.pdf: http://www.t00y.com/file/78256084 [