一文学习 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);
		}
	}
}
事务注解支持的三剑客

AnnotationTransactionAttributeSource

↓(解析注解)

TransactionInterceptor

↓(执行事务逻辑)

BeanFactoryTransactionAttributeSourceAdvisor

↓(组装切点+通知)

总结一下XML入口, 就是无论 xml 支持 还是注解支持都会构造 org.springframework.transaction.interceptor.TransactionInterceptor 这个核心 advice 事务拦截器

对于注解的入口

复制代码
@EnableTransactionManagement
public class TXMain {

	@Transactional
	public static void main(String[] args) throws Exception {
		System.out.println("==========================================================");
		//ApplicationContext context = new ClassPathXmlApplicationContext("application-tx.xml");
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TXMain.class);
		BookService bookService = context.getBean("bookService", BookService.class);
		Book book = new Book();
		book.setName("30秒精通javascript,一分钟精通java");
		book.setCode(""+System.currentTimeMillis());
//		bookService.insertWithTransaction(book );
		bookService.insertWithNoTransaction(book);
		System.out.println("bookService = "+bookService);
		System.out.println("bookService getList = "+bookService.getList());
		System.out.println("==========================================================");
	}
}

@EnableTransactionManagement 注解导入了 TransactionManagementConfigurationSelector 默认选中的是 ProxyTransactionManagementConfiguration

复制代码
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {

	/**
	 * Returns {@link ProxyTransactionManagementConfiguration} or
	 * {@code AspectJ(Jta)TransactionManagementConfiguration} for {@code PROXY}
	 * and {@code ASPECTJ} values of {@link EnableTransactionManagement#mode()},
	 * respectively.
	 */
	@Override
	protected String[] selectImports(AdviceMode adviceMode) {
		return switch (adviceMode) {
		
			case PROXY -> new String[] {AutoProxyRegistrar.class.getName(),
					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);
	}

}
同样注解的三剑客

AnnotationTransactionAttributeSource

↓(解析注解)

TransactionInterceptor

↓(执行事务逻辑)

BeanFactoryTransactionAttributeSourceAdvisor

↓(组装切点+通知)

org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration

复制代码
/*
 * Copyright 2002-2021 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.transaction.annotation;

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

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

	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
			TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {

		BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
		advisor.setTransactionAttributeSource(transactionAttributeSource);
		advisor.setAdvice(transactionInterceptor);
		if (this.enableTx != null) {
			advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
		}
		return advisor;
	}

	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionAttributeSource transactionAttributeSource() {
		// Accept protected @Transactional methods on CGLIB proxies, as of 6.0.
		return new AnnotationTransactionAttributeSource(false);
	}

	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
		TransactionInterceptor interceptor = new TransactionInterceptor();
		interceptor.setTransactionAttributeSource(transactionAttributeSource);
		if (this.txManager != null) {
			interceptor.setTransactionManager(this.txManager);
		}
		return interceptor;
	}

}

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

bean 标签

对于 jdbcTemplate transactionManager dataSource bookService 走的是默认命名空间的处理器, IOC标准解析流程, 不再啰嗦了[[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"));
		}
	}
事务相关对象的BeanDefinition 对应AOP的三剑客

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

对应关系

可以看到少了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;
	}

文章转载自: ++daidaidaiyu++

原文链接: https://www.cnblogs.com/dddy/p/19760461

体验地址: http://www.jnpfsoft.com/?from=0324

相关推荐
毕设源码-钟学长2 小时前
【开题答辩全过程】以 基于SpringBoot的校园快递APP系统的设计与实现为例,包含答辩的问题和答案
java·spring boot·后端
星辰_mya2 小时前
CGLIB 深度解剖:字节码生成的“克隆人”艺术
java·开发语言·面试
云边散步2 小时前
godot2D游戏教程系列二(20)
笔记·学习·音视频
CyanMind2 小时前
IsaacLab 训练范式探索(二):从“上帝视角”到实机落地的蒸馏学习
学习
吃个糖糖2 小时前
Open3D学习点云读取与显示
学习
DANGAOGAO2 小时前
Transformer学习
深度学习·学习·transformer
LSL666_2 小时前
IService——查询(下)
java·开发语言·数据库·mybatisplus·iservice
电子云与长程纠缠2 小时前
Godot学习04 - UI界面
学习·ui·godot
在荒野的梦想2 小时前
Java 调用 OpenAI / Claude API 完整实战指南
java