米嘉怡 发表于 2026-3-23 23:15:02

一文学习 Spring 声明式事务源码全流程总结

Spring 声明式事务源码学习全过程

in short 四步走

[*]Srping 如何从配置中加载的入口
[*]Spring 声明式事务的相关的 BeanDefinition加载流程
[*]Spring 声明式事务的相关对象创建流程
[*]Spring 声明式事务的拦截调用的过程(包括: 方法嵌套, 事务传播属性的处理过程)
最后再看看第三方的框架是如何支持 Spring 声明式事务, 给Spring 托管事务的
一、Spring 声明式事务的入口点

对于XML入口点

XML配置定义
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xmlns:tx="http://www.springframework.org/schema/tx"
           xsi:schemaLocation="
                http://www.springframework.org/schema/beans
                https://www.springframework.org/schema/beans/spring-beans.xsd
                http://www.springframework.org/schema/tx
                https://www.springframework.org/schema/tx/spring-tx.xsd
                http://www.springframework.org/schema/aop
                https://www.springframework.org/schema/aop/spring-aop.xsd">
        <tx:annotation-driven></tx:annotation-driven>

       
        <bean id="jdbcTemplate">
                <property name="dataSource" ref = "dataSource"></property>
        </bean>

       
        <bean id="bookService">
                <property name="jdbcTemplate" ref="jdbcTemplate"></property>
        </bean>
       
        <bean id="dataSource">
                <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
                <property name="url"
       
       
       
       
</aop:config>value="jdbc:mysql://192.168.40.171:3306/workflow_test?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false"/>
                <property name="username" value="user_dev"></property>
                <property name="password" value="dev-sny.com"></property>
        </bean>
       
        <bean id="transactionManager">
                <constructor-arg ref="dataSource"></constructor-arg>
        </bean>
       
               
               
               
               
        </aop:config>

        <tx:advice id="txAdvice" transaction-manager="transactionManager">
                <tx:attributes>
                        <tx:method name="get*" read-only="true"/>
                        <tx:method name="insertWithTransaction" propagation="REQUIRED" />
                        <tx:method name="insertWithNoTransaction" propagation="NEVER" />
                </tx:attributes>
        </tx:advice>
</beans>在XML中配置 tx:.. 启用tx标签, 在解析XML自定义标签时, 会拿到 TxNamespaceHandler 命名空间处理器, 其主要工作就是注册事务相关的标签的解析器

[*]tx:advice 标签解析器:负责XML相关的标签解析 TxAdviceBeanDefinitionParser
[*]tx:annotation-driven 标签解析器:负责注解相关的解析 AnnotationDrivenBeanDefinitionPar
org.springframework.transaction.config.TxNamespaceHandler
public class TxNamespaceHandler extends NamespaceHandlerSupport {

        static final String TRANSACTION_MANAGER_ATTRIBUTE = "transaction-manager";

        static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME = "transactionManager";


        static String getTransactionManagerName(Element element) {
                return (element.hasAttribute(TRANSACTION_MANAGER_ATTRIBUTE) ?
       
       
       
       
</aop:config>element.getAttribute(TRANSACTION_MANAGER_ATTRIBUTE) : DEFAULT_TRANSACTION_MANAGER_BEAN_NAME);
        }


        @Override
        public void init() {
                //<tx:advice> 标签解析器:负责解析XML <tx:advice> 事务标签配置 TxAdviceBeanDefinitionParser
                registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
                //<tx:annotation-driven> 标签解析器:负责解析注解相关的事务配置 AnnotationDrivenBeanDefinitionParser
                registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
                // JTA 规范的分布式事务管理器(管理跨多个资源的事务) TODO
                registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
        }
}启用事务注解支持

class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {

        /**
       * Parses the {@code <tx:annotation-driven/>} tag. Will
       * {@link AopNamespaceUtils#registerAutoProxyCreatorIfNecessary register an AutoProxyCreator}
       * with the container as necessary.
       */
        @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);
                        if (ClassUtils.isPresent("jakarta.transaction.Transactional", getClass().getClassLoader())) {
       
       
       
       
</aop:config>registerJtaTransactionAspect(element, parserContext);
                        }
                }
                else {
                        // 默认是proxy 模式
                        // mode="proxy"
                        AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
                }
                return null;
        }
        注册三剑客
/**
* Inner class to just introduce an AOP framework dependency when actually in proxy mode.
*/
private static class AopAutoProxyConfigurer {

        public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
                AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);

                String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
                if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {
                        Object eleSource = parserContext.extractSource(element);

                        // Create the TransactionAttributeSource definition.
                        RootBeanDefinition sourceDef = new RootBeanDefinition(
       
       
       
       
</aop:config>        "org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
                        sourceDef.setSource(eleSource);
                        sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
                        String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);

                        // Create the TransactionInterceptor definition.
                        RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
                        interceptorDef.setSource(eleSource);
                        interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
                        registerTransactionManager(element, interceptorDef);
                        interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
                        String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);

                        /**
                       * 其中构建事务增强器(BeanFactoryTransactionAttributeSourceAdvisor)
                       * - **Pointcut(切点)**: 默认匹配所有标注 `@Transactional` 的类 / 方法(由 `TransactionAttributeSourcePointcut` 实现)
                       * - **Advice(通知)**: 即 `TransactionInterceptor`(事务拦截器)
                       * - **TransactionAttributeSource(注解解析器)**:即 `AnnotationTransactionAttributeSource`, 负责解析 `@Transactional` 注解的属性(传播行为、隔离级别等)。
                       */
                        // Create the TransactionAttributeSourceAdvisor definition.
                        RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);
                        advisorDef.setSource(eleSource);
                        advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
                        advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
                        advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
                        if (element.hasAttribute("order")) {
       
       
       
       
</aop:config>advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
                        }
                        parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);

                        CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);
                        compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName));
                        compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName));
                        compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, txAdvisorBeanName));
                        parserContext.registerComponent(compositeDef);
                }
        }
}事务注解支持的三剑客


[*]AnnotationTransactionAttributeSource
↓(解析注解)
[*]TransactionInterceptor
↓(执行事务逻辑)
[*]BeanFactoryTransactionAttributeSourceAdvisor
↓(组装切点+通知)
总结一下XML入口, 就是无论 xml 支持 还是注解支持都会构造 org.springframework.transaction.interceptor.TransactionInterceptor 这个核心 advice 事务拦截器
对于注解的入口

@EnableTransactionManagement
public class TXMain {

        @Transactional
        public static void main(String[] args) throws Exception {
                System.out.println("==========================================================");
                //ApplicationContext context = new ClassPathXmlApplicationContext("application-tx.xml");
                AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TXMain.class);
                BookService bookService = context.getBean("bookService", BookService.class);
                Book book = new Book();
                book.setName("30秒精通javascript,一分钟精通java");
                book.setCode(""+System.currentTimeMillis());
//                bookService.insertWithTransaction(book );
                bookService.insertWithNoTransaction(book);
                System.out.println("bookService = "+bookService);
                System.out.println("bookService getList = "+bookService.getList());
                System.out.println("==========================================================");
        }
}@EnableTransactionManagement 注解导入了 TransactionManagementConfigurationSelector 默认选中的是 ProxyTransactionManagementConfiguration
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) {
                return switch (adviceMode) {
               
                        case PROXY -> new String[] {AutoProxyRegistrar.class.getName(),
       
       
       
       
</aop:config>        ProxyTransactionManagementConfiguration.class.getName()};
                        case ASPECTJ -> new String[] {determineTransactionAspectClass()};
                };
        }

        private String determineTransactionAspectClass() {
                return (ClassUtils.isPresent("jakarta.transaction.Transactional", getClass().getClassLoader()) ?
       
       
       
       
</aop:config>TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
       
       
       
       
</aop:config>TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
        }

}同样注解的三剑客


[*]AnnotationTransactionAttributeSource
↓(解析注解)
[*]TransactionInterceptor
↓(执行事务逻辑)
[*]BeanFactoryTransactionAttributeSourceAdvisor
↓(组装切点+通知)
org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration
/*
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.transaction.annotation;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.context.annotation.Role;
import org.springframework.transaction.config.TransactionManagementConfigUtils;
import org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor;
import org.springframework.transaction.interceptor.TransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionInterceptor;

/**
* {@code @Configuration} class that registers the Spring infrastructure beans
* necessary to enable proxy-based annotation-driven transaction management.
*
* @author Chris Beams
* @author Sebastien Deleuze
* @since 3.1
* @see EnableTransactionManagement
* @see TransactionManagementConfigurationSelector
*/
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@ImportRuntimeHints(TransactionRuntimeHints.class)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

        @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() {
                // Accept protected @Transactional methods on CGLIB proxies, as of 6.0.
                return new AnnotationTransactionAttributeSource(false);
        }

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

}总结流程图


二、事务相关的 BeanDefinition 解析过程 (XML)

bean 标签

对于 jdbcTemplate transactionManager dataSource bookService 走的是默认命名空间的处理器, IOC标准解析流程, 不再啰嗦了
[]
org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseBeanDefinitions
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        if (delegate.isDefaultNamespace(root)) {
                NodeList nl = root.getChildNodes();
                for (int i = 0; i < nl.getLength(); i++) {
                        Node node = nl.item(i);
                        if (node instanceof Element ele) {//是否 是元素标签
       
       
       
       
</aop:config>/**
       
       
       
       
</aop:config> * 处理默认命名空间的标签, 有如下四个
       
       
       
       
</aop:config> * <import></import>,</alias>, <bean></bean>, <beans></beans>
       
       
       
       
</aop:config> *
       
       
       
       
</aop:config> */
       
       
       
       
</aop:config>if (delegate.isDefaultNamespace(ele)) {
       
       
       
       
</aop:config>        parseDefaultElement(ele, delegate);
       
       
       
       
</aop:config>}
       
       
       
       
</aop:config>else {
       
       
       
       
</aop:config>        /**
       
       
       
       
</aop:config>       * 处理 非默认命名空间的标签;
       
       
       
       
</aop:config>       *         注意这里包括 <context:bean ...><tx:xx ...> 等等所有指定命名空间的xml配置
       
       
       
       
</aop:config>       *         主要逻辑是: 拿到元素的命名空间URI, 再从 XmlReaderContext 找到对应的 NamespaceHandler 调用解析 `parse`方法解析到 BeanDefinition 返回
       
       
       
       
</aop:config>       */
       
       
       
       
</aop:config>        delegate.parseCustomElement(ele);
       
       
       
       
</aop:config>}
                        }
                }
        }
        else {
                delegate.parseCustomElement(root);
        }
}aop 标签

对于 aop 部分的标签则的是 AOP 的流程
       
       
       
       
</aop:config>
[*] : 解析为 org.springframework.aop.aspectj.AspectJExpressionPointcut 其 BeanDefinition
[*]:解析为 org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor 其 BeanDefinition
internalAutoProxyCreator 的注册

[]
这里要注意AOP 的 ConfigBeanDefinitionParser 在解析时是会注册的一个internalAutoProxyCreator! (AOP解析流程, 在BPP回调时创建代理对象的)
org.springframework.aop.config.ConfigBeanDefinitionParser#parse
        @Override        @Nullable        public BeanDefinition parse(Element element, ParserContext parserContext) {                CompositeComponentDefinition compositeDef =       
       
       
       
</aop:config>new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));                parserContext.pushContainingComponent(compositeDef);                /**               * 1. 注册一个名称为`org.springframework.aop.config.internalAutoProxyCreator` 对AOP处理的Bean Definition; 它是实现 InstantiationAwareBeanPostProcessor 接口的               * 名称是: org.springframework.aop.config.internalAutoProxyCreator               * 对应的类, 根据情况有以下三个可能: org.springframework.aop.config.AopConfigUtils#APC_PRIORITY_LIST               *          InfrastructureAdvisorAutoProxyCreator.class,AspectJAwareAdvisorAutoProxyCreator.class, AnnotationAwareAspectJAutoProxyCreator.class               *         注册一个名称为`org.springframework.aop.config.internalAutoProxyCreator` 对AOP处理的Bean Definition; 它是实现 InstantiationAwareBeanPostProcessor 接口的               *               */                configureAutoProxyCreator(parserContext, element);解析 , , 没有切面标签
org.springframework.aop.config.ConfigBeanDefinitionParser#parse
        @Override        @Nullable        public BeanDefinition parse(Element element, ParserContext parserContext) {                CompositeComponentDefinition compositeDef =       
       
       
       
</aop:config>new CompositeComponentDefinition(element.getTagName(), parserContext.extractSource(element));                parserContext.pushContainingComponent(compositeDef);                /**               * 1. 注册一个名称为`org.springframework.aop.config.internalAutoProxyCreator` 对AOP处理的Bean Definition; 它是实现 InstantiationAwareBeanPostProcessor 接口的               * 名称是: org.springframework.aop.config.internalAutoProxyCreator               * 对应的类, 根据情况有以下三个可能: org.springframework.aop.config.AopConfigUtils#APC_PRIORITY_LIST               *          InfrastructureAdvisorAutoProxyCreator.class,AspectJAwareAdvisorAutoProxyCreator.class, AnnotationAwareAspectJAutoProxyCreator.class               *         注册一个名称为`org.springframework.aop.config.internalAutoProxyCreator` 对AOP处理的Bean Definition; 它是实现 InstantiationAwareBeanPostProcessor 接口的               *               */                configureAutoProxyCreator(parserContext, element);                /**               * 2. 解析标签的子元素 (pointcut, advisor, aspect)               * 解析 :               * 每一个通知(Advice) 都会封装为一个 AspectJPointcutAdvisor 的BeanDefinition 然后将其注册到 BeanFactory               *               *AspectJPointcutAdvisor 的包含情况               * 每一个通知(Advice) 都会封装为一个 AspectJPointcutAdvisor(通知器) 类型的BeanDefinition 然后将其注册到 BeanFactory               *         AspectJPointcutAdvisor 内部包含五种通知类类型:AspectJAfterReturningAdvice AspectJAfterAdvice AspectJAroundAdvice AspectJMethodBeforeAdvice AspectJAfterThrowingAdvice               *而每种通知类型的内部又主要有三个关键属性,包括:               *1. java.lang.reflect.Method(通知切面的方法)               *        2. org.springframework.aop.aspectj.AspectJExpressionPointcut(切入点表达式)               *         3. org.springframework.aop.aspectj.AspectInstanceFactory (切面实例工厂)               */                List childElts = DomUtils.getChildElements(element);                for (Element elt: childElts) {                        String localName = parserContext.getDelegate().getLocalName(elt);                        switch (localName) {       
       
       
       
</aop:config>/**       
       
       
       
</aop:config> * 解析 pointcut/切入点//筛选连接点, 即: 哪些方法需要被代理       
       
       
       
</aop:config> * 解析为 org.springframework.aop.aspectj.AspectJExpressionPointcut 注册其 BeanDefinition       
       
       
       
</aop:config> */       
       
       
       
</aop:config>case POINTCUT -> parsePointcut(elt, parserContext);       
       
       
       
</aop:config>/**       
       
       
       
</aop:config> *解析 advisor/通知/建议/增强处理//即: 增强功能这一部分代码       
       
       
       
</aop:config> * 解析为 org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor 注册其 BeanDefinition       
       
       
       
</aop:config> */       
       
       
       
</aop:config>case ADVISOR -> parseAdvisor(elt, parserContext);       
       
       
       
</aop:config>/**       
       
       
       
</aop:config>       
       
       
       
</aop:config> */       
       
       
       
</aop:config>case ASPECT -> parseAspect(elt, parserContext);                        }                }                parserContext.popAndRegisterContainingComponent();                return null;        }tx 标签

前文说了由 org.springframework.transaction.config.TxAdviceBeanDefinitionParser 负责XML解析
先来到父类方法解析 TransactionInterceptor

org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#parseInternal
/**       * Creates a {@link BeanDefinitionBuilder} instance for the       * {@link #getBeanClass bean Class} and passes it to the       * {@link #doParse} strategy method.       * @param element the element that is to be parsed into a single BeanDefinition       * @param parserContext the object encapsulating the current state of the parsing process       * @return the BeanDefinition resulting from the parsing of the supplied {@link Element}       * @throws IllegalStateException if the bean {@link Class} returned from       * {@link #getBeanClass(org.w3c.dom.Element)} is {@code null}       * @see #doParse       *       */        @Override        protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {                /**               *               * 1. 解析

乐敬 发表于 12 小时前

收藏一下   不知道什么时候能用到
页: [1]
查看完整版本: 一文学习 Spring 声明式事务源码全流程总结