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

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

in short 四步走

  1. Srping 如何从配置中加载的入口
  2. Spring 声明式事务的相关的 BeanDefinition加载流程
  3. Spring 声明式事务的相关对象创建流程
  4. 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>

	<!-- dao bean-->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" >
		<property name="dataSource" ref = "dataSource"></property>
	</bean>

	<!-- service bean-->
	<bean id="bookService" class="org.yang.learn.spring.tx.BookService" >
		<property name="jdbcTemplate" ref="jdbcTemplate"></property>
	</bean>
	<!-- 数据源 bean-->
	<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" >
		<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
		<property name="url"
				  value="jdbc:mysql://192.168.40.171:3306/workflow_test?serverTimezone=Asia/Shanghai&amp;characterEncoding=utf8&amp;useSSL=false"/>
		<property name="username" value="user_dev"></property>
		<property name="password" value="dev-sny.com"></property>
	</bean>
	<!-- 事务管理bean-->
	<bean id="transactionManager" class="org.springframework.jdbc.support.JdbcTransactionManager" >
		<constructor-arg ref="dataSource"></constructor-arg>
	</bean>
	<aop:config>
		<!--切点配置	-->
		<aop:pointcut id="serviceOperation"
					  expression="execution(* org.yang.learn.spring.tx.BookService.*(..))"/>
		<!-- 通知/增强 配置 (关键是这个通知指向 txAdvice '事务增强')-->
		<aop:advisor pointcut-ref="serviceOperation"  advice-ref="txAdvice"/>
	</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) ?
				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())) {
				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(
					"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")) {
				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);
		}
	}
}

事务注解支持的三剑客

  1. AnnotationTransactionAttributeSource
    ↓(解析注解)
  2. TransactionInterceptor
    ↓(执行事务逻辑)
  3. 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(),
					ProxyTransactionManagementConfiguration.class.getName()};
			case ASPECTJ -> new String[] {determineTransactionAspectClass()};
		};
	}

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

}

同样注解的三剑客

  1. AnnotationTransactionAttributeSource
    ↓(解析注解)
  2. TransactionInterceptor
    ↓(执行事务逻辑)
  3. 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;
	}

}

总结流程图

image

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

bean 标签

对于 jdbcTemplate transactionManager dataSource bookService 走的是默认命名空间的处理器, IOC标准解析流程, 不再啰嗦了
[[Spring IOC 源码学习 XML详细加载流程总结]]
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) {//是否 是元素标签
				/**
				 * 处理默认命名空间的标签, 有如下四个
				 * <import></import>, <alias> </alias>, <bean></bean>, <beans></beans>
				 *
				 */
				if (delegate.isDefaultNamespace(ele)) {
					parseDefaultElement(ele, delegate);
				}
				else {
					/**
					 * 处理 非默认命名空间的标签;
					 * 	注意这里包括 <context:bean ...> <aop:xx ...> <tx:xx ...> 等等所有指定命名空间的xml配置
					 * 	主要逻辑是: 拿到元素的命名空间URI, 再从 XmlReaderContext 找到对应的 NamespaceHandler 调用解析 `parse`方法解析到 BeanDefinition 返回
					 */
					delegate.parseCustomElement(ele);
				}
			}
		}
	}
	else {
		delegate.parseCustomElement(root);
	}
}

aop 标签

对于 aop 部分的标签则的是 AOP 的流程

<aop:config>
	<!--切点配置	-->
	<aop:pointcut id="serviceOperation"
				  expression="execution(* org.yang.learn.spring.tx.BookService.*(..))"/>
	<!-- 通知/增强 配置 (关键是这个通知指向 txAdvice '事务增强')-->
	<aop:advisor pointcut-ref="serviceOperation"  advice-ref="txAdvice"/>
</aop:config>
  1. <aop:pointcut... : 解析为 org.springframework.aop.aspectj.AspectJExpressionPointcut 其 BeanDefinition
  2. <aop:advisor... : 解析为 org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor 其 BeanDefinition

internalAutoProxyCreator 的注册

[[Spring AOP 源码学习 详细流程总结]]

这里要注意AOP 的 ConfigBeanDefinitionParser 在解析时是会注册的一个internalAutoProxyCreator! (AOP解析流程, 在BPP回调时创建代理对象的)
org.springframework.aop.config.ConfigBeanDefinitionParser#parse

	@Override
	@Nullable
	public BeanDefinition parse(Element element, ParserContext parserContext) {
		CompositeComponentDefinition compositeDef =
				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);

解析 <aop:pointcut>, <aop:advisor>, 没有切面标签
org.springframework.aop.config.ConfigBeanDefinitionParser#parse


	@Override
	@Nullable
	public BeanDefinition parse(Element element, ParserContext parserContext) {
		CompositeComponentDefinition compositeDef =
				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. 解析 <aop:config> 标签的子元素 (pointcut, advisor, aspect)
		 * 解析 <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<Element> childElts = DomUtils.getChildElements(element);
		for (Element elt: childElts) {
			String localName = parserContext.getDelegate().getLocalName(elt);
			switch (localName) {
				/**
				 * 解析 pointcut/切入点  //筛选连接点, 即: 哪些方法需要被代理
				 * 解析为 org.springframework.aop.aspectj.AspectJExpressionPointcut 注册其 BeanDefinition
				 */
				case POINTCUT -> parsePointcut(elt, parserContext);
				/**
				 *  解析 advisor/通知/建议/增强处理  //即: 增强功能这一部分代码
				 * 解析为 org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor 注册其 BeanDefinition
				 */
				case ADVISOR -> parseAdvisor(elt, parserContext);
				/**
				
				 */
				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. 解析 <tx:advice ... 标签 封装为`GenericBeanDefinition`
		 * 其名称和class为org.springframework.transaction.interceptor.TransactionInterceptor
		 * 注意这个 TransactionInterceptor 实现了MethodInterceptor相当于是个Advice
		 *
		 * org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser
		 * #parseInternal(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext)
		 * org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#parseInternal
		 *
		 *
		 */
		BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
		String parentName = getParentName(element);
		if (parentName != null) {
			builder.getRawBeanDefinition().setParentName(parentName);
		}
		Class<?> beanClass = getBeanClass(element);
		if (beanClass != null) {
			builder.getRawBeanDefinition().setBeanClass(beanClass);
		}
		else {
			String beanClassName = getBeanClassName(element);
			if (beanClassName != null) {
				builder.getRawBeanDefinition().setBeanClassName(beanClassName);
			}
		}
		builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
		BeanDefinition containingBd = parserContext.getContainingBeanDefinition();
		if (containingBd != null) {
			// Inner bean definition must receive same scope as containing bean.
			builder.setScope(containingBd.getScope());
		}
		if (parserContext.isDefaultLazyInit()) {
			// Default-lazy-init applies to custom bean definitions as well.
			builder.setLazyInit(true);
		}
		doParse(element, parserContext, builder);
		return builder.getBeanDefinition();
	}

在回来解析到 transactionAttributeSource

org.springframework.transaction.config.TxAdviceBeanDefinitionParser#doParse

@Override
	protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
		/**
		 * 添加 transactionManager (事务管理)的 ref
		 */
		builder.addPropertyReference("transactionManager", TxNamespaceHandler.getTransactionManagerName(element));
		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) {
			/**
			 * 解析 <tx:attributes> ...  子标签
			 * 包括: 匹配的目标方法, 事务的传播属性, 是否只读..
			 * 类型是 `org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource`
			 */
			// Using attributes source.
			Element attributeSourceElement = txAttributes.get(0);
			RootBeanDefinition attributeSourceDefinition = parseAttributeSource(attributeSourceElement, parserContext);
			builder.addPropertyValue("transactionAttributeSource", attributeSourceDefinition);
		}
		else {
			// Assume annotations source.
			builder.addPropertyValue("transactionAttributeSource",
					new RootBeanDefinition("org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"));
		}
	}

汇总图

image

事务相关对象的BeanDefinition 对应AOP的三剑客

首先一点事务增强, 本质上就是AOP的逻辑, 在AOP最重要的就是AspectJPointcutAdvisor包含的三剑客
image

对应关系
image

可以看到少了AspectInstanceFactory 在事务这里的逻辑中不需它; 因为切面的逻辑是硬编码在TransactionInterceptor中了;

至此在事务相关的AOP对象已经齐了

三、事务增强 相关的对象创建

internalAutoProxyCreator 对象

首先是 internalAutoProxyCreator 它是负责创建AOP对象 它本身是BPP, 它会在 registerBeanPostProcessors(beanFactory); 过程中被实例化
org.springframework.context.support.PostProcessorRegistrationDelegate#registerBeanPostProcessors(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, org.springframework.context.support.AbstractApplicationContext)


	/**
	 *  in short:
	 *  1. 拿到所有实现 BeanPostProcessor 的 bean, 然后进行分类存起来
	 *  这有一点, Spring 对 BeanDefinition 分成三种角色:
	 *  	1. 用户定义的 Bean (ROLE_APPLICATION)
	 *      2. 较复杂的 (ROLE_SUPPORT) 较复杂的? 通常是一个外部配置
	 *      3. Spring 内置的(ROLE_INFRASTRUCTURE)
	 *  2. 如果实现了 BeanPostProcessor 则会实例化这个bean, 但注意这里只是注册,并不会调用BeanPostProcessor的相关方法
	 *
	 *  另外 BeanPostProcessor 粗粒度太大, Spring 还细分一些子接口:
	 *  - SmartInstantiationAwareBeanPostProcessor 它提供了更高级的Bean实例化控制方法。主要作用在于允许对Bean的实例化过程进行更精细的控制和定制。
	 *  - MergedBeanDefinitionPostProcessor 在合并Bean定义(MergedBeanDefinition)之后但在实例化Bean之前,允许对合并后的Bean定义进行修改、调整或附加元数据。
	 *  - DestructionAwareBeanPostProcessor 它允许在Bean被销毁之前(例如,容器关闭或特定作用域的Bean销毁)执行一些操作。
	 */
	public static void registerBeanPostProcessors(
			ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

		// WARNING: Although it may appear that the body of this method can be easily
		// refactored to avoid the use of multiple loops and multiple lists, the use
		// of multiple lists and multiple passes over the names of processors is
		// intentional. We must ensure that we honor the contracts for PriorityOrdered
		// and Ordered processors. Specifically, we must NOT cause processors to be
		// instantiated (via getBean() invocations) or registered in the ApplicationContext
		// in the wrong order.
		//
		// Before submitting a pull request (PR) to change this method, please review the
		// list of all declined PRs involving changes to PostProcessorRegistrationDelegate
		// to ensure that your proposal does not result in a breaking change:
		// https://github.com/spring-projects/spring-framework/issues?q=PostProcessorRegistrationDelegate+is%3Aclosed+label%3A%22status%3A+declined%22
		/**
		 * 拿到所有实现 BeanPostProcessor 的 bean名称
		 */
		String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

		// Register BeanPostProcessorChecker that logs an info message when
		// a bean is created during BeanPostProcessor instantiation, i.e. when
		// a bean is not eligible for getting processed by all BeanPostProcessors.
		/**
		 * 计算 BeanPostProcessor(BPP) 的总数.
		 * +1 是什么操作? 原因是: 下一行,又加了一个 BeanPostProcessorChecker
		 */
		int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
		// BeanPostProcessorChecker 这个BeanPostProcessor, 没啥实际作用, 就是记录了一些日志;
		beanFactory.addBeanPostProcessor(
				new BeanPostProcessorChecker(beanFactory, postProcessorNames, beanProcessorTargetCount));
		// Separate between BeanPostProcessors that implement PriorityOrdered,
		// Ordered, and the rest.
		/**
		 * 对 BeanPostProcessor 进行分类存起来,  再调用, 每个集合分别是
		 * 1. priorityOrderedPostProcessors //有实现(PriorityOrdered)排序接口的
		 * 2. internalPostProcessors //Spring内部的bean, 见: Spring将bean分为三种角色
		 * 3. orderedPostProcessorNames //实现 Ordered 接口
		 * 4. nonOrderedPostProcessorNames //没有指定顺序, 无序的
		 */
		List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
		List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
		List<String> orderedPostProcessorNames = new ArrayList<>();
		List<String> nonOrderedPostProcessorNames = new ArrayList<>();
		for (String ppName : postProcessorNames) {
			if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				/**
				 * 注意, 若 bean 实现了 PriorityOrdered 接口, 则会优先实例化它;
				 */
				BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
				priorityOrderedPostProcessors.add(pp);
				if (pp instanceof MergedBeanDefinitionPostProcessor) {
					internalPostProcessors.add(pp);
				}
			}
			else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
				orderedPostProcessorNames.add(ppName);
			}
			else {
				nonOrderedPostProcessorNames.add(ppName);
			}
		}

		// First, register the BeanPostProcessors that implement PriorityOrdered.
		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

		// Next, register the BeanPostProcessors that implement Ordered.
		List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
		for (String ppName : orderedPostProcessorNames) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			orderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}
		sortPostProcessors(orderedPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, orderedPostProcessors);

		/**
		 * 注册所有常规BeanPostProcessors
		 * 这里 getBean 实例化bean !;
		 */
		// Now, register all regular(常规) BeanPostProcessors.
		List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
		for (String ppName : nonOrderedPostProcessorNames) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			nonOrderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}
		registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

		/**
		 * 最后, 注册所有 内置 BeanPostProcessor
		 */
		// Finally, re-register all internal BeanPostProcessors.
		sortPostProcessors(internalPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, internalPostProcessors);

		//最后再放一个 ApplicationListenerDetector 让它在最后 (不是重点, 见名应该是事件相关的)
		// Re-register post-processor for detecting inner beans as ApplicationListeners,
		// moving it to the end of the processor chain (for picking up proxies etc).
		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
	}

DefaultBeanFactoryPointcutAdvisor 和 AspectJExpressionPointcut 对象

internalAutoProxyCreator 会在 postProcessBeforeInstantiation 回调中的org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#shouldSkip判断时实例化所有的 Advisor

在实例化 Advisor 填充属性时也会把 AspectJExpressionPointcut 也实例化

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessBeforeInstantiation

@Override
	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {

		/**
		 * 常规情况下:  这里只是检查下缓存和标记缓存
		 * 对于真正的AOP代理创建见:
		 * {@link AbstractAutoProxyCreator#postProcessAfterInitialization(java.lang.Object, java.lang.String)}
		 */
		Object cacheKey = getCacheKey(beanClass, beanName);
		if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {

			/**
			 *
			 *  不管需不需要, 只要处理过了就缓存
			 * 	advisedBeans 这个变量, 缓存所有处理过的 bean名称;
			 * 	value 为 boolean值, 如果为false 则不处理
			 */
			if (this.advisedBeans.containsKey(cacheKey)) {
				return null;
			}
			/**
			 * isInfrastructureClass 是否是基础功能类,即 AOP相关的几个类:
			 * Advice.class Pointcut.class Advisor.class AopInfrastructureBean.class 都为true
			 *
			 * shouldSkip 判断时, 拿到容器的所有 Advisor, 并且实例化 `getBean()` 这个 Advisor
			 */
			if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
				this.advisedBeans.put(cacheKey, Boolean.FALSE);
				return null;
			}
		}

		// Create proxy here if we have a custom TargetSource.
		// Suppresses unnecessary default instantiation of the target bean:
		// The TargetSource will handle target instances in a custom fashion.
		TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
		if (targetSource != null) {
			if (StringUtils.hasLength(beanName)) {
				this.targetSourcedBeans.add(beanName);
			}
			Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
			Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

		return null;
	}

TransactionInterceptort 对象

是在 internalAutoProxyCreator 遇到需要增强代理的对象时, 这里是 bookService 去 getAdvicesAndAdvisorsForBean 查找到其匹配 bookService 的 Advisor
这里若 Advisor 匹配, 会调用 getAdvice 获取其切面, 此时切面不存在则会实例化它

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#wrapIfNecessary

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
		if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
			return bean;
		}
		if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
			return bean;
		}
		if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
			this.advisedBeans.put(cacheKey, Boolean.FALSE);
			return bean;
		}
		/**
		 * 拿到所有匹配织入当前bean的 所有通知器(Advisor)
		 * 做了三件事, 见: {@link org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean(java.lang.Class, java.lang.String, org.springframework.aop.TargetSource)}
		 * 1. 往返回 `AspectJXXXAdvice`列表数组`0`索引 插入一个{@link org.springframework.aop.interceptor.ExposeInvocationInterceptor} 实例
		 * 方便传递参数用的
		 *
		 * 2. 怎么匹配(Advisor)?
		 * Advisor中的 `AspectJExpressionPointcut` 是实现 {@link ClassFilter} 和 {@link org.springframework.aop.MethodMatcher} 接口
		 * 一个进行类匹配, 一个进行方法匹配. Advisor 匹配会调用 getAdvice 获取其切面, 此时切面不存在则会实例化
		 *
		 * 3.  排序, 基于 `有向无环` 图进行排序; 可能匹配到多个切面(aspect)
		 *
		 */
		// Create proxy if we have advice.
		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
		if (specificInterceptors != DO_NOT_PROXY) {
			/**
			 *{@link org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#advisedBeans}
			 * 这个变量缓存所有处理过的 bean名称, value 为 boolean值, 如果为false 则不处理
			 */
			this.advisedBeans.put(cacheKey, Boolean.TRUE);//缓存, 表示已处理
			/**
			 * 创建代理
			 *
			 */
			Object proxy = createProxy(
					bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
			this.proxyTypes.put(cacheKey, proxy.getClass());
			return proxy;
		}

		this.advisedBeans.put(cacheKey, Boolean.FALSE);
		return bean;
	}

汇总图

image

四、事务增强 相关的方法调用流程

对于嵌套事务关键两个对象

首先梳理一下, 这里最复杂的问题是有多层方法嵌套的事务时, 对于事务的传播特性, 应该如何处理?
因为整个处理流程中涉及的对象非常多, 对于理解这里面的逻辑最为关键的对象有两个 TransactionStatus 和 TransactionInfo

TransactionInfo

该对象是在事务多层嵌套时流转的核心对象, 它几乎持有事务相关的所有对象
org.springframework.transaction.interceptor.TransactionAspectSupport.TransactionInfo

/**
 * Opaque object used to hold transaction information. Subclasses
 * must pass it back to methods on this class, but not see its internals.
 */
protected static final class TransactionInfo {

	// 1. 事务管理器(DataSource/JPA等事务管理器)
	private final PlatformTransactionManager transactionManager;

	// 2. 事务属性(传播行为、隔离级别、超时、只读等)
	private final TransactionAttribute transactionAttribute;

	// 3. 切入的目标方法名(用于日志、异常追踪)
	private final String joinpointIdentification;

	// 4. 真实的事务状态(Spring 事务核心状态对象)
	private TransactionStatus transactionStatus;

	// 5. 上一个事务信息(处理事务嵌套/挂起,形成链表)
	private TransactionInfo previousTransactionInfo;

	@Nullable
	private TransactionInfo oldTransactionInfo;

	public TransactionInfo(@Nullable PlatformTransactionManager transactionManager,
			@Nullable TransactionAttribute transactionAttribute, String joinpointIdentification) {

		this.transactionManager = transactionManager;
		this.transactionAttribute = transactionAttribute;
		this.joinpointIdentification = joinpointIdentification;
	}

	public PlatformTransactionManager getTransactionManager() {
		Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
		return this.transactionManager;
	}

	@Nullable
	public TransactionAttribute getTransactionAttribute() {
		return this.transactionAttribute;
	}

	/**
	 * Return a String representation of this joinpoint (usually a Method call)
	 * for use in logging.
	 */
	public String getJoinpointIdentification() {
		return this.joinpointIdentification;
	}

	public void newTransactionStatus(@Nullable TransactionStatus status) {
		this.transactionStatus = status;
	}

	@Nullable
	public TransactionStatus getTransactionStatus() {
		return this.transactionStatus;
	}

	/**
	 * Return whether a transaction was created by this aspect,
	 * or whether we just have a placeholder to keep ThreadLocal stack integrity.
	 */
	public boolean hasTransaction() {
		return (this.transactionStatus != null);
	}

	private void bindToThread() {
		// Expose current TransactionStatus, preserving any existing TransactionStatus
		// for restoration after this transaction is complete.
		this.oldTransactionInfo = transactionInfoHolder.get();
		transactionInfoHolder.set(this);
	}

	private void restoreThreadLocalStatus() {
		// Use stack to restore old transaction TransactionInfo.
		// Will be null if none was set.
		transactionInfoHolder.set(this.oldTransactionInfo);
	}

	@Override
	public String toString() {
		return (this.transactionAttribute != null ? this.transactionAttribute.toString() : "No transaction");
	}
}
// 1. 事务管理器(DataSource/JPA等事务管理器)
private final PlatformTransactionManager transactionManager;

// 2. 事务属性(传播行为、隔离级别、超时、只读等)
private final TransactionAttribute transactionAttribute;

// 3. 切入的目标方法名(用于日志、异常追踪)
private final String joinpointIdentification;

// 4. 真实的事务状态(Spring 事务核心状态对象)
private TransactionStatus transactionStatus;

// 5. 上一个事务信息(处理事务嵌套/挂起,形成链表)
private TransactionInfo previousTransactionInfo;

@Nullable
private TransactionInfo oldTransactionInfo;

记录了当前线程正在执行的事务所有关键信息,支撑事务的开启、挂起、恢复、提交 / 回滚全流程

对于这个状态对象关键的点是, 在多层嵌套时;
org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction

  • 在每次嵌套时都会调用 bindToThread
private void bindToThread() {
	// Expose current TransactionStatus, preserving any existing TransactionStatus
	// for restoration after this transaction is complete.
	this.oldTransactionInfo = transactionInfoHolder.get();
	transactionInfoHolder.set(this);
}

保存上一个 TransactionInfo

  • 在嵌套方法结束返回是调用 restoreThreadLocalStatus
private void restoreThreadLocalStatus() {
	// Use stack to restore old transaction TransactionInfo.
	// Will be null if none was set.
	transactionInfoHolder.set(this.oldTransactionInfo);
}

恢复上一个 TransactionInfo

TransactionStatus

org.springframework.transaction.TransactionStatus

public interface TransactionStatus extends TransactionExecution, SavepointManager, Flushable {

	/**
	 * Return whether this transaction internally carries a savepoint,
	 * that is, has been created as nested transaction based on a savepoint.
	 * <p>This method is mainly here for diagnostic purposes, alongside
	 * {@link #isNewTransaction()}. For programmatic handling of custom
	 * savepoints, use the operations provided by {@link SavepointManager}.
	 * <p>The default implementation returns {@code false}.
	 * @see #isNewTransaction()
	 * @see #createSavepoint()
	 * @see #rollbackToSavepoint(Object)
	 * @see #releaseSavepoint(Object)
	 */
	default boolean hasSavepoint() {
		return false;
	}

	/**
	 * Flush the underlying session to the datastore, if applicable:
	 * for example, all affected Hibernate/JPA sessions.
	 * <p>This is effectively just a hint and may be a no-op if the underlying
	 * transaction manager does not have a flush concept. A flush signal may
	 * get applied to the primary resource or to transaction synchronizations,
	 * depending on the underlying resource.
	 * <p>The default implementation is empty, considering flush as a no-op.
	 */
	@Override
	default void flush() {
	}

}

大部分属性其实都在它的父类 TransactionExecution
org.springframework.transaction.TransactionExecution


package org.springframework.transaction;

/**
 * Common representation of the current state of a transaction.
 * Serves as base interface for {@link TransactionStatus} as well as
 * {@link ReactiveTransaction}, and as of 6.1 also as transaction
 * representation for {@link TransactionExecutionListener}.
 *
 * @author Juergen Hoeller
 * @since 5.2
 */
public interface TransactionExecution {

	/**
	 * Return the defined name of the transaction (possibly an empty String).
	 * <p>In case of Spring's declarative transactions, the exposed name will be
	 * the {@code fully-qualified class name + "." + method name} (by default).
	 * <p>The default implementation returns an empty String.
	 * @since 6.1
	 * @see TransactionDefinition#getName()
	 */
	default String getTransactionName() {
		return "";
	}

	/**
	 * Return whether there is an actual transaction active: this is meant to cover
	 * a new transaction as well as participation in an existing transaction, only
	 * returning {@code false} when not running in an actual transaction at all.
	 * <p>The default implementation returns {@code true}.
	 * @since 6.1
	 * @see #isNewTransaction()
	 * @see #isNested()
	 * @see #isReadOnly()
	 */
	default boolean hasTransaction() {
		return true;
	}

	/**
	 * Return whether the transaction manager considers the present transaction
	 * as new; otherwise participating in an existing transaction, or potentially
	 * not running in an actual transaction in the first place.
	 * <p>This is primarily here for transaction manager state handling.
	 * Prefer the use of {@link #hasTransaction()} for application purposes
	 * since this is usually semantically appropriate.
	 * <p>The "new" status can be transaction manager specific, e.g. returning
	 * {@code true} for an actual nested transaction but potentially {@code false}
	 * for a savepoint-based nested transaction scope if the savepoint management
	 * is explicitly exposed (such as on {@link TransactionStatus}). A combined
	 * check for any kind of nested execution is provided by {@link #isNested()}.
	 * <p>The default implementation returns {@code true}.
	 * @see #hasTransaction()
	 * @see #isNested()
	 * @see TransactionStatus#hasSavepoint()
	 */
	default boolean isNewTransaction() {
		return true;
	}

	/**
	 * Return if this transaction executes in a nested fashion within another.
	 * <p>The default implementation returns {@code false}.
	 * @since 6.1
	 * @see #hasTransaction()
	 * @see #isNewTransaction()
	 * @see TransactionDefinition#PROPAGATION_NESTED
	 */
	default boolean isNested() {
		return false;
	}

	/**
	 * Return if this transaction is defined as read-only transaction.
	 * <p>The default implementation returns {@code false}.
	 * @since 6.1
	 * @see TransactionDefinition#isReadOnly()
	 */
	default boolean isReadOnly() {
		return false;
	}

	/**
	 * Set the transaction rollback-only. This instructs the transaction manager
	 * that the only possible outcome of the transaction may be a rollback, as
	 * alternative to throwing an exception which would in turn trigger a rollback.
	 * <p>The default implementation throws an UnsupportedOperationException.
	 * @see #isRollbackOnly()
	 */
	default void setRollbackOnly() {
		throw new UnsupportedOperationException("setRollbackOnly not supported");
	}

	/**
	 * Return whether the transaction has been marked as rollback-only
	 * (either by the application or by the transaction infrastructure).
	 * <p>The default implementation returns {@code false}.
	 * @see #setRollbackOnly()
	 */
	default boolean isRollbackOnly() {
		return false;
	}

	/**
	 * Return whether this transaction is completed, that is,
	 * whether it has already been committed or rolled back.
	 * <p>The default implementation returns {@code false}.
	 */
	default boolean isCompleted() {
		return false;
	}

}

// 1. 是否是新事务
boolean isNewTransaction();

// 2. 是否标记为 只回滚
boolean isRollbackOnly();

// 3. 事务是否已完成(提交/回滚)
boolean isCompleted();

// 4. 是否是只读事务
boolean isReadOnly();

// 5. 是否被标记为 必须回滚
default boolean isRollbackOnly()

in short 可以理解为一个事务的状态: 是否是新事务, 是否是序列化, 是否是嵌套, 是否是只读的等

对于这个状态对象关键的点是, 在多层嵌套时, 主要在:
org.springframework.transaction.support.AbstractPlatformTransactionManager#handleExistingTransaction
视情况(主要是根据事务的传播特性, 该方法也是处理多层事务的核心方法) 创建或修改事务状态中的属性

对于线程绑定事务管理对象 TransactionSynchronizationManager

org.springframework.transaction.support.TransactionSynchronizationManager

public abstract class TransactionSynchronizationManager {

	/**
	 * 线程私有事务资源
	 */
	private static final ThreadLocal<Map<Object, Object>> resources =
			new NamedThreadLocal<>("Transactional resources");

	/**
	 * 事务同步?
	 */
	private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
			new NamedThreadLocal<>("Transaction synchronizations");

	/**
	 * 当前事务的 名称
	 */
	private static final ThreadLocal<String> currentTransactionName =
			new NamedThreadLocal<>("Current transaction name");
	/**
	 * 当前事务 是否只读
	 */
	private static final ThreadLocal<Boolean> currentTransactionReadOnly =
			new NamedThreadLocal<>("Current transaction read-only status");
	/**
	 * 当前事务的 隔离级别
	 */
	private static final ThreadLocal<Integer> currentTransactionIsolationLevel =
			new NamedThreadLocal<>("Current transaction isolation level");
	/**
	 * 事务是否实际激活
	 */
	private static final ThreadLocal<Boolean> actualTransactionActive =
			new NamedThreadLocal<>("Actual transaction active");
			
	
	/**
	 * Retrieve a resource for the given key that is bound to the current thread.
	 * @param key the key to check (usually the resource factory)
	 * @return a value bound to the current thread (usually the active
	 * resource object), or {@code null} if none
	 * @see ResourceTransactionManager#getResourceFactory()
	 */
	@Nullable
	public static Object getResource(Object key) {
		Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
		return doGetResource(actualKey);
	}
	/**
	 * Actually check the value of the resource that is bound for the given key.
	 */
	@Nullable
	private static Object doGetResource(Object actualKey) {
		Map<Object, Object> map = resources.get();
		if (map == null) {
			return null;
		}
		Object value = map.get(actualKey);
		// Transparently remove ResourceHolder that was marked as void...
		if (value instanceof ResourceHolder resourceHolder && resourceHolder.isVoid()) {
			map.remove(actualKey);
			// Remove entire ThreadLocal if empty...
			if (map.isEmpty()) {
				resources.remove();
			}
			value = null;
		}
		return value;
	}
	
	/**
	 * Bind the given resource for the given key to the current thread.
	 * @param key the key to bind the value to (usually the resource factory)
	 * @param value the value to bind (usually the active resource object)
	 * @throws IllegalStateException if there is already a value bound to the thread
	 * @see ResourceTransactionManager#getResourceFactory()
	 */
	public static void bindResource(Object key, Object value) throws IllegalStateException {
		Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
		Assert.notNull(value, "Value must not be null");
		Map<Object, Object> map = resources.get();
		// set ThreadLocal Map if none found
		if (map == null) {
			map = new HashMap<>();
			resources.set(map);
		}
		Object oldValue = map.put(actualKey, value);
		// Transparently suppress a ResourceHolder that was marked as void...
		if (oldValue instanceof ResourceHolder resourceHolder && resourceHolder.isVoid()) {
			oldValue = null;
		}
		if (oldValue != null) {
			throw new IllegalStateException(
					"Already value [" + oldValue + "] for key [" + actualKey + "] bound to thread");
		}
	}
	...........

可以看到有相当多的 ThreadLocal 变量, 它就是负责将事务信息与当前线程绑定的

绑定的源码逻辑
org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin

/**
 *
 * 真正在数据库中支持事务,
 * 1. 从数据源中获取链接
 * 2. 设置事务的隔离级别
 * 3. 关闭连接的自动提交
 * 4. 绑定连接到线程中 TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
 *
 * so , 如果想要复用或者是适配 Spring 的事务支持的数据库连接可以这么拿:
 * ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
 *
 */
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
	DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
	Connection con = null;

	try {
		/**
		 * 如果 ConnectionHolder 中没有数据库连接 则从数据源中获取,再存到[事务上下文] txObject对象中
		 * (真正的从数据源获取JDBC连接)
		 */
		if (!txObject.hasConnectionHolder() ||
				txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
			Connection newCon = obtainDataSource().getConnection();
			if (logger.isDebugEnabled()) {
				logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
			}
			txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
		}
		txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
		con = txObject.getConnectionHolder().getConnection();
		/**
		 * 设置事务隔离级别
		 */
		Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
		txObject.setPreviousIsolationLevel(previousIsolationLevel);
		txObject.setReadOnly(definition.isReadOnly());

		// Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
		// so we don't want to do it unnecessarily (for example if we've explicitly
		// configured the connection pool to set it already).
		/**
		 * 关闭自动提交, 由 Spring 负责管理了
		 */
		if (con.getAutoCommit()) {
			txObject.setMustRestoreAutoCommit(true);
			if (logger.isDebugEnabled()) {
				logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
			}
			con.setAutoCommit(false);
		}
		/**
		 * 判断是否 需要设置为只读事务
		 */
		prepareTransactionalConnection(con, definition);
		txObject.getConnectionHolder().setTransactionActive(true);

		int timeout = determineTimeout(definition);
		if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
			txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
		}

		/**
		 * 如果是新的连接 (也可以理解为新事务)
		 * 绑定到线程中
		 */
		// Bind the connection holder to the thread.
		if (txObject.isNewConnectionHolder()) {
			/**
			 * 将 ConnectionHolder 绑定到当前线程中 (ThreadLocal)
			 *
			 * 如果想要复用或者是适配 Spring 的事务支持可以这么拿:
			 * ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
			 * 数据库的连接
			 *
			 * > ConnectionHolder 可以理解为包装了数据库的连接, 不重要
			 */
			TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
		}
	}

	catch (Throwable ex) {
		if (txObject.isNewConnectionHolder()) {
			DataSourceUtils.releaseConnection(con, obtainDataSource());
			txObject.setConnectionHolder(null, false);
		}
		throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
	}
}

获取/复用的数据库连接的源码逻辑
org.springframework.jdbc.datasource.DataSourceTransactionManager#doGetTransaction

@Override
	protected Object doGetTransaction() {
		/**
		 * 1. 创建一个DataSourceTransactionObject  封装对象, 可以理解为数据源上下文, 它包含:
		 * ConnectionHolder 数据库连接Holder对象
		 * newConnectionHolder : 是否是新连接 属性
		 * savepointAllowed: 是否允许'保存点'
		 * readOnly: 是否只读
		 *
		 */
		DataSourceTransactionObject txObject = new DataSourceTransactionObject();
		//
		/**
		 * 设置允许'保存点'
		 */
		txObject.setSavepointAllowed(isNestedTransactionAllowed());
		/**
		 *  2. 从[事务同步管理器]中获取连接持有器, Holder 持有一个数据库连接, 如果是第一次获取则是 null
		 *  事务同步管理器: (TransactionSynchronizationManager): 该对象管理的资源都是绑定到当前事务中的; 内部使用的 ThreadLocal 存储的
		 *  如果没有事务, 第一次获取则是 null,
		 *  如果之前有事务, 将会获取的同一个 ConnectionHolder
		 *  将获取到的ConnectionHolder 存到 DataSourceTransactionObject
		 *
		 *  总之核心逻辑就是复用事务连接
		 */
		ConnectionHolder conHolder =
				(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
		txObject.setConnectionHolder(conHolder, false);
		/**
		 * 放到 事务上下文
		 */
		return txObject;
	}

重中之重的是: 的第三方扩展库/框架 都是通过这种方式支持Spring 声明式事务的, 见后文!

关键的源码流程

拦截器主流程入口

org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction

/**
	 * General delegate for around-advice-based subclasses, delegating to several other template
	 * methods on this class. Able to handle {@link CallbackPreferringPlatformTransactionManager}
	 * as well as regular {@link PlatformTransactionManager} implementations and
	 * {@link ReactiveTransactionManager} implementations for reactive return types.
	 * @param method the Method being invoked
	 * @param targetClass the target class that we're invoking the method on
	 * @param invocation the callback to use for proceeding with the target invocation
	 * @return the return value of the method, if any
	 * @throws Throwable propagated from the target invocation
	 */
	@Nullable
	protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
			final InvocationCallback invocation) throws Throwable {

		/**
		 * 获取事务属性源
		 * 即: <tx:attributes> 标签配置的
		 */
		// If the transaction attribute is null, the method is non-transactional.
		TransactionAttributeSource tas = getTransactionAttributeSource();
		/**
		 * 1. 通过目标方法去匹配, 拿到对应的属性配置(TransactionAttribute), 比如: 是否只读, 事务传播属性, rollbackOn 等
		 */
		final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
		/**
		 * 2. 拿到对应的事务管理器对象 (bean) TransactionManager
		 */
		final TransactionManager tm = determineTransactionManager(txAttr);

		if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager rtm) {
			boolean isSuspendingFunction = KotlinDetector.isSuspendingFunction(method);
			boolean hasSuspendingFlowReturnType = isSuspendingFunction &&
					COROUTINES_FLOW_CLASS_NAME.equals(new MethodParameter(method, -1).getParameterType().getName());
			if (isSuspendingFunction && !(invocation instanceof CoroutinesInvocationCallback)) {
				throw new IllegalStateException("Coroutines invocation not supported: " + method);
			}
			CoroutinesInvocationCallback corInv = (isSuspendingFunction ? (CoroutinesInvocationCallback) invocation : null);
			ReactiveTransactionSupport txSupport = this.transactionSupportCache.computeIfAbsent(method, key -> {
				Class<?> reactiveType =
						(isSuspendingFunction ? (hasSuspendingFlowReturnType ? Flux.class : Mono.class) : method.getReturnType());
				ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(reactiveType);
				if (adapter == null) {
					throw new IllegalStateException("Cannot apply reactive transaction to non-reactive return type: " +
							method.getReturnType());
				}
				return new ReactiveTransactionSupport(adapter);
			});
			InvocationCallback callback = invocation;
			if (corInv != null) {
				callback = () -> KotlinDelegate.invokeSuspendingFunction(method, corInv);
			}
			return txSupport.invokeWithinTransaction(method, targetClass, callback, txAttr, rtm);
		}

		PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
		/**
		 * 3. 生成获取到事务方法的唯一ID
		 */
		final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

		if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager cpptm)) {
			/**
			 * 4. 使用 TransactionManager 创建事务, 获取到事务信息对象 (TransactionInfo)
			 */
			// Standard transaction demarcation with getTransaction and commit/rollback calls.
			TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

			Object retVal;
			try {
				/**
				 * 5. 以事务执行调用, 回调方法
				 * retVal 是dao方法(原始方法) 执行的返回值
				 */
				// This is an around advice: Invoke the next interceptor in the chain.
				// This will normally result in a target object being invoked.
				retVal = invocation.proceedWithInvocation();
			}
			catch (Throwable ex) {
				/**
				 * 6. 执行异常, 执行异常回滚操作
				 */
				// target invocation exception
				completeTransactionAfterThrowing(txInfo, ex);

				/**
				 * 注意这里还要再抛出去, 给外层事务知道 内层执行出现异常
				 */
				throw ex;
			}
			finally {
				/**
				 * 7. 不管异常与否, 清除当前线程的[事务上下文]信息
				 * 这个是在{@link org.springframework.transaction.interceptor.TransactionAspectSupport#createTransactionIfNecessary(org.springframework.transaction.PlatformTransactionManager, org.springframework.transaction.interceptor.TransactionAttribute, java.lang.String)}
				 * 中返回时 prepareTransactionInfo方法中,调用了 `txInfo.newTransactionStatus(status);` 保存到 ThreadLocal 中的
				 */
				cleanupTransactionInfo(txInfo);
			}

			if (retVal != null && txAttr != null) {
				TransactionStatus status = txInfo.getTransactionStatus();
				if (status != null) {
					if (retVal instanceof Future<?> future && future.isDone()) {
						try {
							future.get();
						}
						catch (ExecutionException ex) {
							if (txAttr.rollbackOn(ex.getCause())) {
								status.setRollbackOnly();
							}
						}
						catch (InterruptedException ex) {
							Thread.currentThread().interrupt();
						}
					}
					else if (vavrPresent && VavrDelegate.isVavrTry(retVal)) {
						// Set rollback-only in case of Vavr failure matching our rollback rules...
						retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
					}
				}
			}

			/**
			 * 8. 执行正常,执行正常提交处理
			 */
			commitTransactionAfterReturning(txInfo);
			return retVal;
		}

		else {
			
		.....
	}

创建 TransactionInfo

使用 TransactionManager 创建事务, 获取到事务的上下文对象 (TransactionInfo)

org.springframework.transaction.interceptor.TransactionAspectSupport#createTransactionIfNecessary

protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
			@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {

		/**
		 * 包装了一下事务源属性
		 */
		// If no name specified, apply method identification as transaction name.
		if (txAttr != null && txAttr.getName() == null) {
			txAttr = new DelegatingTransactionAttribute(txAttr) {
				@Override
				public String getName() {
					return joinpointIdentification;
				}
			};
		}
		/**
		 * 获取[事务状态]: 表示
		 * 是否 新事务
		 * 是否 有保存点
		 * 是否 只回滚
		 * 是否 完成
		 */
		TransactionStatus status = null;
		if (txAttr != null) {
			if (tm != null) {
				/**
				 *  1. 获取到一个封装对象: 可以理解为事务的状态
				 *  * 它包括: 是否只读, 是否允许'保存点', 从[事务同步管理器]获取 ConnectionHolder (注意第一次获取'无事务', Holder的connect是null的 );
				 *
				 *  2. 判断当前是否存在事务, 判断依据是 ConnectionHolder 内部 Active 标识符
				 *	 * 如果存在则, 处理事务传播特性
				 *   * {@link org.springframework.transaction.support.AbstractPlatformTransactionManager#handleExistingTransaction(org.springframework.transaction.TransactionDefinition, java.lang.Object, boolean)}
				 *
				 *  3. 判断一下当前事务传播特性, 创建新的事务
				 * 	 * 在这里如果是 REQUIRED, REQUIRES_NEW, NESTED 传播特性, 才需要需要创建事务
				 *
				 *  4. 开始事务
				 * 	创建一个[事务状态]对象, 如果没有 数据库连接 则从数据源 中获取, 封装为 ConnectionHolder, 并赋值给[事务上下文]对象
				 * 	开始事务, 其实就是设置数据库连接的一些属性:
				 * 	  关闭自动提交, 由Spring 负责管理了
				 * 	  判断是否需要设置为只读事务
				 * 	  如果是新事务, 则绑定到当前线程中 (ThreadLocal)
				 *  org.springframework.transaction.support.AbstractPlatformTransactionManager#startTransaction(org.springframework.transaction.TransactionDefinition, java.lang.Object, boolean, boolean, org.springframework.transaction.support.AbstractPlatformTransactionManager.SuspendedResourcesHolder)
				 *
				 * 见 {@link org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction(org.springframework.transaction.TransactionDefinition)}
				 */
				status = tm.getTransaction(txAttr);
			}
			else {
				if (logger.isDebugEnabled()) {
					logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
							"] because no transaction manager has been configured");
				}
			}
		}
		/**
		 * 见: {@link org.springframework.transaction.interceptor.TransactionAspectSupport#prepareTransactionInfo(org.springframework.transaction.PlatformTransactionManager, org.springframework.transaction.interceptor.TransactionAttribute, java.lang.String, org.springframework.transaction.TransactionStatus)}
		 */
		return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
	}

获取事务

org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction

/**
	 * This implementation handles propagation behavior. Delegates to
	 * {@code doGetTransaction}, {@code isExistingTransaction}
	 * and {@code doBegin}.
	 * @see #doGetTransaction
	 * @see #isExistingTransaction
	 * @see #doBegin
	 */
	@Override
	public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
			throws TransactionException {

		/**
		 * 将 TransactionStatus 和 事务方法唯一ID, 事务源属性 封装为 TransactionDefinition
		 */
		// Use defaults if no transaction definition given.
		TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());

		/**
		 * 1. 获取到一个封装对象(DataSourceTransactionObject): 可以理解为事务上下文
		 * 它包括: 是否只读, 是否允许'保存点', 从[事务同步管理器]获取到的 ConnectionHolder (注意第一次'无事务'获取的 连接持有器Holder的connect是null的 );
		 *
		 * [事务同步管理器](TransactionSynchronizationManager): 该对象管理的资源都是绑定到当前事务中的; 内部使用ThreadLocal 存储的
		 * org.springframework.jdbc.datasource.DataSourceTransactionManager#doGetTransaction()  设置允许'保存点'
		 */
		Object transaction = doGetTransaction();
		boolean debugEnabled = logger.isDebugEnabled();

		/**
		 * 2. 判断当前是否存在事务, 判断依据是 ConnectionHolder 内部 Active 标识符
		 * 如果存在则, 处理事务传播特性
		 * org.springframework.transaction.support.AbstractPlatformTransactionManager#handleExistingTransaction(org.springframework.transaction.TransactionDefinition, java.lang.Object, boolean)
		 */
		if (isExistingTransaction(transaction)) {
			/**
			 * 如果当前存在事务, 则走这个分支
			 */
			// Existing transaction found -> check propagation behavior to find out how to behave.
			return handleExistingTransaction(def, transaction, debugEnabled);
		}

		// Check definition settings for new transaction.
		if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
			throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
		}
		/**
		 * 3. 判断一下当前事务传播特性, 创建新的事务
		 * 在这里如果是 REQUIRED, REQUIRES_NEW, NESTED 传播特性, 需要创建事务
		 */
		// No existing transaction found -> check propagation behavior to find out how to proceed.
		if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
			throw new IllegalTransactionStateException(
					"No existing transaction found for transaction marked with propagation 'mandatory'");
		}
		else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
				def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
				def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
			/**
			 * 挂起事务 (当前没有事务)
			 */
			SuspendedResourcesHolder suspendedResources = suspend(null);
			if (debugEnabled) {
				logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
			}
			try {
				/**
				 *  4. 开始事务
				 *   * 创建一个[事务状态]对象, 关键属性: 是否是新的、是否有保存点、是否只读、是否嵌套、是否为只回滚、是否完成。
				 *   * 如果没有 数据库连接 则从数据源 中获取, 封装为 ConnectionHolder, 并赋值给[事务上下文]对象
				 * 	  * 其实就是设置数据库连接的一些属性:
				 * 	  * 关闭自动提交, 由Spring 负责管理了
				 * 	  * 判断是否需要设置为只读事务
				 * 	  * 如果是新事务, 则通过 [事务同步资源管理器] TransactionSynchronizationManager 绑定到当前线程中 (ThreadLocal)
				 */
				return startTransaction(def, transaction, false, debugEnabled, suspendedResources);
			}
			catch (RuntimeException | Error ex) {
				resume(null, suspendedResources);
				throw ex;
			}
		}
		else {
			// Create "empty" transaction: no actual transaction, but potentially synchronization.
			if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
				logger.warn("Custom isolation level specified but no actual transaction initiated; " +
						"isolation level will effectively be ignored: " + def);
			}
			boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
			return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
		}
	}
在已有事务的情况-处理事务的传播特性

在已有事务的情况下, 主要是处理事务的传播特性
org.springframework.transaction.support.AbstractPlatformTransactionManager#handleExistingTransaction

/**
	 * Create a TransactionStatus for an existing transaction.
	 */
	private TransactionStatus handleExistingTransaction(
			TransactionDefinition definition, Object transaction, boolean debugEnabled)
			throws TransactionException {
		/**
		 * 注意一点 , 现在是外部有事务的情况
		 * transaction 是txObject
		 */

		/**
		 * 1.如果是 NEVER (不允许事务) 传播特性, 则抛出异常
		 */
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
			throw new IllegalTransactionStateException(
					"Existing transaction found for transaction marked with propagation 'never'");
		}
		/**
		 * 2.如果是 NOT_SUPPORTED (不支持当前事务;总是以非事务的方式执行), 传播特性 挂起事务
		 */
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
			if (debugEnabled) {
				logger.debug("Suspending current transaction");
			}
			//挂起事务
			Object suspendedResources = suspend(transaction);
			boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
			// 返回一个 无事务状态(TransactionStatus)
			return prepareTransactionStatus(
					definition, null, false, newSynchronization, debugEnabled, suspendedResources);
		}

		/**
		 * 3.如果是 REQUIRES_NEW 传播特性, 挂起当前事务
		 * 注意该特性:
		 * - 事务挂起后, 新的事务是完全独立的, 包括连接等等, 每个事务独立提交
		 * - 它的内层事务影响外层事务, 但是外层异常不影响内层事务
		 */
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
			if (debugEnabled) {
				logger.debug("Suspending current transaction, creating new transaction with name [" +
						definition.getName() + "]");
			}

			/**
			 * 挂起当前事务, 何为挂起?
			 * 如果有事务的话
			 *  1. 将 DataSourceTransactionObject [事务上下文]中的 ConnectionHolder 设置为null
			 * 	2. 从[事务同步管理器]中解除绑定: TransactionSynchronizationManager.unbindResource(obtainDataSource())
			 * 	  这样就拿不到对象,不会对事务资源进行复用
			 * 	3. 挂起了, 下次还有恢复, 所以要保存被挂起的事务信息 (SuspendedResourcesHolder)
			 *
			 */
			SuspendedResourcesHolder suspendedResources = suspend(transaction);
			try {

				/**
				 *  //开启新的事务
				 */
				return startTransaction(definition, transaction, false, debugEnabled, suspendedResources);
			}
			catch (RuntimeException | Error beginEx) {
				resumeAfterBeginException(transaction, suspendedResources, beginEx);
				throw beginEx;
			}
		}
		/**
		 * 4.如果是 NESTED (总是以嵌套的方式执行, 可以无限嵌套, MySQL的实现是 基于事务的保存点 savepoint )传播特性
		 */
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
			if (!isNestedTransactionAllowed()) {
				throw new NestedTransactionNotSupportedException(
						"Transaction manager does not allow nested transactions by default - " +
						"specify 'nestedTransactionAllowed' property with value 'true'");
			}
			if (debugEnabled) {
				logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
			}
			/**
			 * 使用保存点, 对于NESTED的事务 (空实现,恒等于true)
			 */
			if (useSavepointForNestedTransaction()) {
				/**
				 * 4.1 创建一个新的[事务状态] DefaultTransactionStatus
				 */
				// Create savepoint within existing Spring-managed transaction,
				// through the SavepointManager API implemented by TransactionStatus.
				// Usually uses JDBC savepoints. Never activates Spring synchronization.
				DefaultTransactionStatus status = newTransactionStatus(
						definition, transaction, false, false, true, debugEnabled, null);
				this.transactionExecutionListeners.forEach(listener -> listener.beforeBegin(status));
				try {
					/**
					 * 4.2 创建保存点
					 * 最终是使用 ConnectionHolder 进行创建保存点, 底层是调用JDBC的接口方法 java.sql.Connection#setSavepoint(java.lang.String)
					 * org.springframework.jdbc.datasource.ConnectionHolder#createSavepoint()
					 */
					status.createAndHoldSavepoint();
				}
				catch (RuntimeException | Error ex) {
					this.transactionExecutionListeners.forEach(listener -> listener.afterBegin(status, ex));
					throw ex;
				}
				this.transactionExecutionListeners.forEach(listener -> listener.afterBegin(status, null));
				return status;
			}
			else {
				// Nested transaction through nested begin and commit/rollback calls.
				// Usually only for JTA: Spring synchronization might get activated here
				// in case of a pre-existing JTA transaction.
				return startTransaction(definition, transaction, true, debugEnabled, null);
			}
		}

		// Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.
		if (debugEnabled) {
			logger.debug("Participating in existing transaction");
		}
		if (isValidateExistingTransaction()) {
			if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
				Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
				if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) {
					throw new IllegalTransactionStateException("Participating transaction with definition [" +
							definition + "] specifies isolation level which is incompatible with existing transaction: " +
							(currentIsolationLevel != null ?
									DefaultTransactionDefinition.getIsolationLevelName(currentIsolationLevel) :
									"(unknown)"));
				}
			}
			if (!definition.isReadOnly()) {
				if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
					throw new IllegalTransactionStateException("Participating transaction with definition [" +
							definition + "] is not marked as read-only but existing transaction is");
				}
			}
		}
		boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
		return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
	}

无事务的情况-新建事务

org.springframework.transaction.support.AbstractPlatformTransactionManager#startTransaction

/**
 * Start a new transaction.
 */
private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
		boolean nested, boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {

	boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);

	/**
	 * 1. 创建一个[事务状态]对象
	 * 包括事务: 是否是新的、是否有保存点、是否只读、是否嵌套、是否为只回滚、是否完成。
	 */
	DefaultTransactionStatus status = newTransactionStatus(
			definition, transaction, true, newSynchronization, nested, debugEnabled, suspendedResources);
	this.transactionExecutionListeners.forEach(listener -> listener.beforeBegin(status));
	try {
		/**
		 * 2. 如果没有 数据库连接 则从数据源 中获取, 封装为 ConnectionHolder, 并赋值给[事务上下文]对象
		 * 设置数据库连的一些属性:
		 *  关闭自动提交, 由Spring 负责管理了
		 *  判断是否需要设置为只读事务
		 *  如果是新事务, 则绑定到当前线程中 (ThreadLocal)
		 *
		 *  {@link org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin(java.lang.Object, org.springframework.transaction.TransactionDefinition)}
		 */
		doBegin(transaction, definition);
	}
	catch (RuntimeException | Error ex) {
		this.transactionExecutionListeners.forEach(listener -> listener.afterBegin(status, ex));
		throw ex;
	}
	prepareSynchronization(status, definition);
	this.transactionExecutionListeners.forEach(listener -> listener.afterBegin(status, null));
	return status;
}

事务方法执行异常情况

org.springframework.transaction.interceptor.TransactionAspectSupport#completeTransactionAfterThrowing

/**
	 * Handle a throwable, completing the transaction.
	 * We may commit or roll back, depending on the configuration.
	 * @param txInfo information about the current transaction
	 * @param ex throwable encountered
	 */
	protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
		if (txInfo != null && txInfo.getTransactionStatus() != null) {
			if (logger.isTraceEnabled()) {
				logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
						"] after exception: " + ex);
			}
			/**
			 * 1. 匹配回滚的异常
			 *  txInfo.transactionAttribute.rollbackOn(ex) 匹配回滚的异常
			 */
			if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
				try {
					/**
					 * 2. 设置回滚状态
					 */
					txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
				}
				catch (TransactionSystemException ex2) {
					logger.error("Application exception overridden by rollback exception", ex);
					ex2.initApplicationException(ex);
					throw ex2;
				}
				catch (RuntimeException | Error ex2) {
					logger.error("Application exception overridden by rollback exception", ex);
					throw ex2;
				}
			}
			else {
				// We don't roll back on this exception.
				// Will still roll back if TransactionStatus.isRollbackOnly() is true.
				try {
					txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
				}
				catch (TransactionSystemException ex2) {
					logger.error("Application exception overridden by commit exception", ex);
					ex2.initApplicationException(ex);
					throw ex2;
				}
				catch (RuntimeException | Error ex2) {
					logger.error("Application exception overridden by commit exception", ex);
					throw ex2;
				}
			}
		}
	}

事务方法执行正常情况

org.springframework.transaction.interceptor.TransactionAspectSupport#commitTransactionAfterReturning

	/**
	 * Execute after successful completion of call, but not after an exception was handled.
	 * Do nothing if we didn't create a transaction.
	 * @param txInfo information about the current transaction
	 */
	protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
		if (txInfo != null && txInfo.getTransactionStatus() != null) {
			if (logger.isTraceEnabled()) {
				logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
			}
			/**
			 * 获取到当前的 TransactionStatus 提交到 TransactionManager
			 * 注意并不一定是数据库提交, 取决与 TransactionStatus 的状态实现, 有可能是回滚, 空提交
			 */
			txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
		}
	}

嵌套恢复线程中 TransactionInfo 信息

这个是在{@link org.springframework.transaction.interceptor.TransactionAspectSupport#createTransactionIfNecessary(org.springframework.transaction.PlatformTransactionManager, org.springframework.transaction.interceptor.TransactionAttribute, java.lang.String)}
中返回时 prepareTransactionInfo方法中,调用了 txInfo.newTransactionStatus(status); 保存到 ThreadLocal 中的

/**
 * Reset the TransactionInfo ThreadLocal.
 * <p>Call this in all cases: exception or normal return!
 * @param txInfo information about the current transaction (may be {@code null})
 */
protected void cleanupTransactionInfo(@Nullable TransactionInfo txInfo) {
	if (txInfo != null) {
		txInfo.restoreThreadLocalStatus();
	}
}

调用流程汇总图

image
https://img2024.cnblogs.com/blog/3723410/202603/3723410-20260323222541707-574711567.png

底层处理事务的源码

事务的开启

如果ConnectionHolder 中没有数据库连接 则从数据源中获取, (真正的从数据源获取JDBC连接), 关闭自动提交,绑定到线程
org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin

/**
 *
 * 真正在数据库中支持事务,
 * 1. 从数据源中获取链接
 * 2. 设置事务的隔离级别
 * 3. 关闭连接的自动提交
 * 4. 绑定连接到线程中 TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
 * so , 如果想要复用或者是适配 Spring 的事务支持的数据库连接可以这么拿:
 * ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
 *
 */
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
	DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
	Connection con = null;
	try {
		/**
		 * 如果ConnectionHolder 中没有数据库连接 则从数据源中获取,再存到[事务上下文]对象中
		 * (真正的从数据源获取JDBC连接)
		 */
		if (!txObject.hasConnectionHolder() ||
				txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
			Connection newCon = obtainDataSource().getConnection();
			if (logger.isDebugEnabled()) {
				logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
			}
			txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
		}
		txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
		con = txObject.getConnectionHolder().getConnection();
		/**
		 * 设置事务隔离级别
		 */
		Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
		txObject.setPreviousIsolationLevel(previousIsolationLevel);
		txObject.setReadOnly(definition.isReadOnly());

		// Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
		// so we don't want to do it unnecessarily (for example if we've explicitly
		// configured the connection pool to set it already).
		/**
		 * 关闭自动提交, 由 Spring 负责管理了
		 */
		if (con.getAutoCommit()) {
			txObject.setMustRestoreAutoCommit(true);
			if (logger.isDebugEnabled()) {
				logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
			}
			con.setAutoCommit(false);
		}
		/**
		 * 判断是否 需要设置为只读事务
		 */
		prepareTransactionalConnection(con, definition);
		txObject.getConnectionHolder().setTransactionActive(true);

		int timeout = determineTimeout(definition);
		if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
			txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
		}

		/**
		 * 如果是新的连接 (也可以理解为新事务)
		 */
		// Bind the connection holder to the thread.
		if (txObject.isNewConnectionHolder()) {
			/**  
			 * 将 ConnectionHolder 绑定到当前线程中 (ThreadLocal)  
			 * 下次再拿的话可以这么拿:  
			 * ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource()); * * > 可以理解 ConnectionHolder 包装了数据库的连接  
			 */
			TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
		}
	}

	catch (Throwable ex) {
		if (txObject.isNewConnectionHolder()) {
			DataSourceUtils.releaseConnection(con, obtainDataSource());
			txObject.setConnectionHolder(null, false);
		}
		throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
	}
}

事务的提交

判断一下 TransactionStatus 中状态, 决定是否要回滚
org.springframework.transaction.support.AbstractPlatformTransactionManager#commit


/**
 * This implementation of commit handles participating in existing
 * transactions and programmatic rollback requests.
 * Delegates to {@code isRollbackOnly}, {@code doCommit}
 * and {@code rollback}.
 * @see org.springframework.transaction.TransactionStatus#isRollbackOnly()
 * @see #doCommit
 * @see #rollback
 */
@Override
public final void commit(TransactionStatus status) throws TransactionException {
	if (status.isCompleted()) {
		throw new IllegalTransactionStateException(
				"Transaction is already completed - do not call commit or rollback more than once per transaction");
	}

	DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
	/**
	 * 1. 判断 [事务状态] 是否设置了回滚
	 */
	if (defStatus.isLocalRollbackOnly()) {
		if (defStatus.isDebug()) {
			logger.debug("Transactional code has requested rollback");
		}
		processRollback(defStatus, false);
		return;
	}
	/**
	 * 2. 判断 [事务状态] 是否设置了设置了全局回滚
	 * 这里会拿到 ConnectHolder 判断其回滚标记
	 */
	if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
		if (defStatus.isDebug()) {
			logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
		}
		processRollback(defStatus, true);
		return;
	}
	/**
	 * 3. 处理提交
	 */
	processCommit(defStatus);
}

触发一些钩子, 只有是 最外层事务才真正的JDBC提交
org.springframework.transaction.support.AbstractPlatformTransactionManager#processCommit

private void processCommit(DefaultTransactionStatus status) throws TransactionException {
		try {
			boolean beforeCompletionInvoked = false;
			boolean commitListenerInvoked = false;

			try {
				boolean unexpectedRollback = false;
				//预留 hook方法
				prepareForCommit(status);

				triggerBeforeCommit(status);
				triggerBeforeCompletion(status);
				beforeCompletionInvoked = true;


				if (status.hasSavepoint()) {
					/**
					 * 1. 是否有事务保存点 (NESTED 才会有保存点)
					 * 有就释放保存点
					 */
					if (status.isDebug()) {
						logger.debug("Releasing transaction savepoint");
					}
					unexpectedRollback = status.isGlobalRollbackOnly();
					this.transactionExecutionListeners.forEach(listener -> listener.beforeCommit(status));
					commitListenerInvoked = true;
					status.releaseHeldSavepoint();
				}
				else if (status.isNewTransaction()) {
					/**
					 * 2. 是否是新事务, 即 是最外层事务才真正的JDBC提交
					 */
					if (status.isDebug()) {
						logger.debug("Initiating transaction commit");
					}
					unexpectedRollback = status.isGlobalRollbackOnly();
					this.transactionExecutionListeners.forEach(listener -> listener.beforeCommit(status));
					commitListenerInvoked = true;

					/**
					 * 真正的JDBC提交
					 */
					doCommit(status);
				}
				......

真正的 JDBC层提交
org.springframework.jdbc.datasource.DataSourceTransactionManager#doCommit

@Override  
protected void doCommit(DefaultTransactionStatus status) {  
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();  
    Connection con = txObject.getConnectionHolder().getConnection();  
    if (status.isDebug()) {  
       logger.debug("Committing JDBC transaction on Connection [" + con + "]");  
    }    try {  
       con.commit();  
    }    catch (SQLException ex) {  
       throw translateException("JDBC commit", ex);  
    }}

事务的回滚

跟提交同理, 只有最外层的才应该真正的提交
org.springframework.transaction.support.AbstractPlatformTransactionManager#processRollback

/**
	 * Process an actual rollback.
	 * The completed flag has already been checked.
	 * @param status object representing the transaction
	 * @throws TransactionException in case of rollback failure
	 */
	private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
		try {
			boolean unexpectedRollback = unexpected;
			boolean rollbackListenerInvoked = false;
			try {
				/**
				 * 1. 如果事务状态有保存点, 将事务状态回滚到设置的保存点 (仅NESTED才会存在保存点)
				 */
				triggerBeforeCompletion(status);
				if (status.hasSavepoint()) {
					if (status.isDebug()) {
						logger.debug("Rolling back transaction to savepoint");
					}
					this.transactionExecutionListeners.forEach(listener -> listener.beforeRollback(status));
					rollbackListenerInvoked = true;
					status.rollbackToHeldSavepoint();
				}
				else if (status.isNewTransaction()) {
					/**
					 * 2. 如果是新(外层)事务的话, 真正执行回滚 (只有在最外层是执行回滚的)
					 */
					if (status.isDebug()) {
						logger.debug("Initiating transaction rollback");
					}
					this.transactionExecutionListeners.forEach(listener -> listener.beforeRollback(status));
					rollbackListenerInvoked = true;
					/**
					 * 真正在数据库连接层 执行事务回滚
					 */
					doRollback(status);
				}
				else {
					// Participating in larger transaction
					if (status.hasTransaction()) {
						if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
							if (status.isDebug()) {
								logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
							}
							/**
							 *  3. 设置 ConnectionHolder 中的 RollbackOnly 标记状态
							 */
							doSetRollbackOnly(status);
						}
						else {
							if (status.isDebug()) {
								logger.debug("Participating transaction failed - letting transaction originator decide on rollback");
							}
						}
					}
					else {
						logger.debug("Should roll back transaction but cannot - no transaction available");
					}
					// Unexpected rollback only matters here if we're asked to fail early
					if (!isFailEarlyOnGlobalRollbackOnly()) {
						/**
						 * 4. 设置非预期的回滚标记
						 */
						unexpectedRollback = false;
					}
				}
			}
			catch (RuntimeException | Error ex) {
				triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
				if (rollbackListenerInvoked) {
					this.transactionExecutionListeners.forEach(listener -> listener.afterRollback(status, ex));
				}
				throw ex;
			}

			triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
			if (rollbackListenerInvoked) {
				this.transactionExecutionListeners.forEach(listener -> listener.afterRollback(status, null));
			}

			// Raise UnexpectedRollbackException if we had a global rollback-only marker
			if (unexpectedRollback) {
				throw new UnexpectedRollbackException(
						"Transaction rolled back because it has been marked as rollback-only");
			}
		}
		finally {
			/**
			 * 5. 清除当前事务信息, 注意, 这里如果有被挂起的事务还会恢复它
			 */
			cleanupAfterCompletion(status);
		}
	}

真正的 JDBC层回滚
org.springframework.jdbc.datasource.DataSourceTransactionManager#doRollback

	@Override
	protected void doRollback(DefaultTransactionStatus status) {
		DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
		Connection con = txObject.getConnectionHolder().getConnection();
		if (status.isDebug()) {
			logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");
		}
		try {
			con.rollback();
		}
		catch (SQLException ex) {
			throw translateException("JDBC rollback", ex);
		}
	}

最后, 看看第三方框架是如何支持Spring声明式事务的

JdbcTemplate 是怎么支持Spring声明式事务的?

org.springframework.jdbc.core.JdbcTemplate
关键在于确保数据源中获取的 JDBC连接 都是同一个, 而在声明式事务配置中, 无论是 dataSource 对象, 还是 jdbcTemplate Bean 都没有被代理; 从配置上, 来看也完全没有关联

其实是 JdbcTemplate 在获取连接时 适配了 Spring 事务相关的代码, 关键源码:

  • org.springframework.jdbc.core.JdbcTemplate#execute(org.springframework.jdbc.core.CallableStatementCreator, org.springframework.jdbc.core.CallableStatementCallback<T>)
  • org.springframework.jdbc.datasource.DataSourceUtils#getConnection
  • org.springframework.jdbc.datasource.DataSourceUtils#doGetConnection
public static Connection doGetConnection(DataSource dataSource) throws SQLException {  
   Assert.notNull(dataSource, "No DataSource specified");  
	//从 TransactionSynchronizationManager 获取连接 (由Spring声明式事务处理的连接)
   ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);  
   if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {  
      conHolder.requested();  
      if (!conHolder.hasConnection()) {  
         logger.debug("Fetching resumed JDBC Connection from DataSource");  
         conHolder.setConnection(fetchConnection(dataSource));  
      }  
      return conHolder.getConnection();  
   }  
   // Else we either got no holder or an empty thread-bound holder here.  
   logger.debug("Fetching JDBC Connection from DataSource");  
   Connection con = fetchConnection(dataSource);
......

MyBatis 是怎么支持Spring声明式事务的?

org.mybatis.spring.transaction.SpringManagedTransaction

org.springframework.jdbc.datasource.DataSourceUtils#doGetConnection

/**
	 * Actually obtain a JDBC Connection from the given DataSource.
	 * Same as {@link #getConnection}, but throwing the original SQLException.
	 * <p>Is aware of a corresponding Connection bound to the current thread, for example
	 * when using {@link DataSourceTransactionManager}. Will bind a Connection to the thread
	 * if transaction synchronization is active (for example, if in a JTA transaction).
	 * <p>Directly accessed by {@link TransactionAwareDataSourceProxy}.
	 * @param dataSource the DataSource to obtain Connections from
	 * @return a JDBC Connection from the given DataSource
	 * @throws SQLException if thrown by JDBC methods
	 * @see #doReleaseConnection
	 */
	public static Connection doGetConnection(DataSource dataSource) throws SQLException {
		Assert.notNull(dataSource, "No DataSource specified");

		ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
		if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {
			conHolder.requested();
			if (!conHolder.hasConnection()) {
				logger.debug("Fetching resumed JDBC Connection from DataSource");
				conHolder.setConnection(fetchConnection(dataSource));
			}
			return conHolder.getConnection();
		}
		// Else we either got no holder or an empty thread-bound holder here.

		logger.debug("Fetching JDBC Connection from DataSource");
		Connection con = fetchConnection(dataSource);

		if (TransactionSynchronizationManager.isSynchronizationActive()) {
			try {
				// Use same Connection for further JDBC actions within the transaction.
				// Thread-bound object will get removed by synchronization at transaction completion.
				ConnectionHolder holderToUse = conHolder;
				if (holderToUse == null) {
					holderToUse = new ConnectionHolder(con);
				}
				else {
					holderToUse.setConnection(con);
				}
				holderToUse.requested();
				TransactionSynchronizationManager.registerSynchronization(
						new ConnectionSynchronization(holderToUse, dataSource));
				holderToUse.setSynchronizedWithTransaction(true);
				if (holderToUse != conHolder) {
					TransactionSynchronizationManager.bindResource(dataSource, holderToUse);
				}
			}
			catch (RuntimeException ex) {
				// Unexpected exception from external delegation call -> close Connection and rethrow.
				releaseConnection(con, dataSource);
				throw ex;
			}
		}

		return con;
	}

Hibernate 是怎么支持Spring声明式事务的?

  1. 开启事务的源码
@Override
	protected void doBegin(Object transaction, TransactionDefinition definition) {
		HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;

		if (txObject.hasConnectionHolder() && !txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
			throw new IllegalTransactionStateException(
					"Pre-bound JDBC Connection found! HibernateTransactionManager does not support " +
					"running within DataSourceTransactionManager if told to manage the DataSource itself. " +
					"It is recommended to use a single HibernateTransactionManager for all transactions " +
					"on a single DataSource, no matter whether Hibernate or JDBC access.");
		}

		SessionImplementor session = null;

		try {
			if (!txObject.hasSessionHolder() || txObject.getSessionHolder().isSynchronizedWithTransaction()) {
				Interceptor entityInterceptor = getEntityInterceptor();
				Session newSession = (entityInterceptor != null ?
						obtainSessionFactory().withOptions().interceptor(entityInterceptor).openSession() :
						obtainSessionFactory().openSession());
				if (this.sessionInitializer != null) {
					this.sessionInitializer.accept(newSession);
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Opened new Session [" + newSession + "] for Hibernate transaction");
				}
				txObject.setSession(newSession);
			}

			session = txObject.getSessionHolder().getSession().unwrap(SessionImplementor.class);

			boolean holdabilityNeeded = this.allowResultAccessAfterCompletion && !txObject.isNewSession();
			boolean isolationLevelNeeded = (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT);
			if (holdabilityNeeded || isolationLevelNeeded || definition.isReadOnly()) {
				if (this.prepareConnection && ConnectionReleaseMode.ON_CLOSE.equals(
						session.getJdbcCoordinator().getLogicalConnection().getConnectionHandlingMode().getReleaseMode())) {
					// We're allowed to change the transaction settings of the JDBC Connection.
					if (logger.isDebugEnabled()) {
						logger.debug("Preparing JDBC Connection of Hibernate Session [" + session + "]");
					}
					Connection con = session.connection();
					Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
					txObject.setPreviousIsolationLevel(previousIsolationLevel);
					txObject.setReadOnly(definition.isReadOnly());
					if (this.allowResultAccessAfterCompletion && !txObject.isNewSession()) {
						int currentHoldability = con.getHoldability();
						if (currentHoldability != ResultSet.HOLD_CURSORS_OVER_COMMIT) {
							txObject.setPreviousHoldability(currentHoldability);
							con.setHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT);
						}
					}
					txObject.connectionPrepared();
				}
				else {
					// Not allowed to change the transaction settings of the JDBC Connection.
					if (isolationLevelNeeded) {
						// We should set a specific isolation level but are not allowed to...
						throw new InvalidIsolationLevelException(
								"HibernateTransactionManager is not allowed to support custom isolation levels: " +
								"make sure that its 'prepareConnection' flag is on (the default) and that the " +
								"Hibernate connection release mode is set to ON_CLOSE.");
					}
					if (logger.isDebugEnabled()) {
						logger.debug("Not preparing JDBC Connection of Hibernate Session [" + session + "]");
					}
				}
			}

			if (definition.isReadOnly() && txObject.isNewSession()) {
				// Just set to MANUAL in case of a new Session for this transaction.
				session.setHibernateFlushMode(FlushMode.MANUAL);
				// As of 5.1, we're also setting Hibernate's read-only entity mode by default.
				session.setDefaultReadOnly(true);
			}

			if (!definition.isReadOnly() && !txObject.isNewSession()) {
				// We need AUTO or COMMIT for a non-read-only transaction.
				FlushMode flushMode = session.getHibernateFlushMode();
				if (FlushMode.MANUAL.equals(flushMode)) {
					session.setHibernateFlushMode(FlushMode.AUTO);
					txObject.getSessionHolder().setPreviousFlushMode(flushMode);
				}
			}

			Transaction hibTx;

			// Register transaction timeout.
			int timeout = determineTimeout(definition);
			if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
				// Use Hibernate's own transaction timeout mechanism on Hibernate 3.1+
				// Applies to all statements, also to inserts, updates and deletes!
				hibTx = session.getTransaction();
				hibTx.setTimeout(timeout);
				hibTx.begin();
			}
			else {
				// Open a plain Hibernate transaction without specified timeout.
				hibTx = session.beginTransaction();
			}

			// Add the Hibernate transaction to the session holder.
			txObject.getSessionHolder().setTransaction(hibTx);

			// Register the Hibernate Session's JDBC Connection for the DataSource, if set.
			if (getDataSource() != null) {
				ConnectionHolder conHolder = new ConnectionHolder(session::connection);
				if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
					conHolder.setTimeoutInSeconds(timeout);
				}
				if (logger.isDebugEnabled()) {
					logger.debug("Exposing Hibernate transaction as JDBC [" + conHolder.getConnectionHandle() + "]");
				}
				TransactionSynchronizationManager.bindResource(getDataSource(), conHolder);
				txObject.setConnectionHolder(conHolder);
			}
			// 绑定到线程
			// Bind the session holder to the thread.
			if (txObject.isNewSessionHolder()) {
				TransactionSynchronizationManager.bindResource(obtainSessionFactory(), txObject.getSessionHolder());
			}
			txObject.getSessionHolder().setSynchronizedWithTransaction(true);
		}

		catch (Throwable ex) {
			if (txObject.isNewSession()) {
				try {
					if (session != null && session.getTransaction().getStatus() == TransactionStatus.ACTIVE) {
						session.getTransaction().rollback();
					}
				}
				catch (Throwable ex2) {
					logger.debug("Could not rollback Session after failed transaction begin", ex);
				}
				finally {
					SessionFactoryUtils.closeSession(session);
					txObject.setSessionHolder(null);
				}
			}
			throw new CannotCreateTransactionException("Could not open Hibernate Session for transaction", ex);
		}
	}
  1. 复用的源码
    org.springframework.orm.hibernate5.SpringSessionContext#currentSession
/**
	 * Retrieve the Spring-managed Session for the current thread, if any.
	 */
	@Override
	public Session currentSession() throws HibernateException {
		Object value = TransactionSynchronizationManager.getResource(this.sessionFactory);
		if (value instanceof Session) {
			return (Session) value;
		}
		else if (value instanceof SessionHolder) {
			// HibernateTransactionManager
			SessionHolder sessionHolder = (SessionHolder) value;
			Session session = sessionHolder.getSession();
			if (!sessionHolder.isSynchronizedWithTransaction() &&
					TransactionSynchronizationManager.isSynchronizationActive()) {
				TransactionSynchronizationManager.registerSynchronization(
						new SpringSessionSynchronization(sessionHolder, this.sessionFactory, false));
				sessionHolder.setSynchronizedWithTransaction(true);
				// Switch to FlushMode.AUTO, as we have to assume a thread-bound Session
				// with FlushMode.MANUAL, which needs to allow flushing within the transaction.
				FlushMode flushMode = session.getHibernateFlushMode();
				if (flushMode.equals(FlushMode.MANUAL) &&
						!TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
					session.setHibernateFlushMode(FlushMode.AUTO);
					sessionHolder.setPreviousFlushMode(flushMode);
				}
			}
			return session;
		}
		else if (value instanceof EntityManagerHolder) {
			// JpaTransactionManager
			return ((EntityManagerHolder) value).getEntityManager().unwrap(Session.class);
		}

		if (this.transactionManager != null && this.jtaSessionContext != null) {
			try {
				if (this.transactionManager.getStatus() == Status.STATUS_ACTIVE) {
					Session session = this.jtaSessionContext.currentSession();
					if (TransactionSynchronizationManager.isSynchronizationActive()) {
						TransactionSynchronizationManager.registerSynchronization(
								new SpringFlushSynchronization(session));
					}
					return session;
				}
			}
			catch (SystemException ex) {
				throw new HibernateException("JTA TransactionManager found but status check failed", ex);
			}
		}

		if (TransactionSynchronizationManager.isSynchronizationActive()) {
			Session session = this.sessionFactory.openSession();
			if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
				session.setHibernateFlushMode(FlushMode.MANUAL);
			}
			SessionHolder sessionHolder = new SessionHolder(session);
			TransactionSynchronizationManager.registerSynchronization(
					new SpringSessionSynchronization(sessionHolder, this.sessionFactory, true));
			TransactionSynchronizationManager.bindResource(this.sessionFactory, sessionHolder);
			sessionHolder.setSynchronizedWithTransaction(true);
			return session;
		}
		else {
			throw new HibernateException("Could not obtain transaction-synchronized Session for current thread");
		}
	}
posted @ 2026-03-23 22:26  daidaidaiyu  阅读(9)  评论(0)    收藏  举报