前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring事务管理---下

Spring事务管理---下

作者头像
大忽悠爱学习
发布2022-06-19 13:41:00
5480
发布2022-06-19 13:41:00
举报
文章被收录于专栏:c++与qt学习c++与qt学习

Spring事务管理---下


本系列文章:

Spring事务管理—中

Spring事务管理—上

Spring事务王国概览


前文,我们已经完成了对注解元数据驱动的声明式事务的模拟实现,并且详细分析了模拟实现的流程和原理,下面我将带领各位来看看Spring真正的源码实现,让大家真正掌握Spring事务的精髓。


注解元数据驱动的声明式事务

在不使用SpringBoot自动配置的情况下,开启注解元数据驱动的声明式事务有两种方式:

  • 在配置文件中加上下面这句话
代码语言:javascript
复制
 <tx:annotation-driven transaction-manager="transactionManager" mode="proxy" proxy-target-class="true"/>
  • 或者在配置类上加上下面这个注解
代码语言:javascript
复制
@EnableTransactionManagement

tx:annotation-driven源码追踪

想要进行测试,可以引入下面这段xml配置:

代码语言:javascript
复制
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
">
 <tx:annotation-driven mode="proxy" proxy-target-class="true"/>
</beans>

tx:annotation-driven标签中的mode属性和proxy-target-class属性,如果看过我上篇模拟注解驱动声明式事务的文章应该都清楚,我们自定义的注解:

代码语言:javascript
复制
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(MyTransactionManagementConfigurationSelector.class)
public @interface MyEnableTransactionManagement {

    /**
     * 是否默认采用cglib进行代理
     */
    boolean proxyTargetClass() default false;

    /**
     * 代理模式--是jdk,cglib代理还是aspectj代理
     */
    AdviceMode mode() default AdviceMode.PROXY;
}

设置了这两个属性,目的在于能够去创建自动代理创建器,这里一样。

tx:annotation-driven不属于Spring默认命名空间,属于自定义命名空间,那么肯定存在相关的tx命名空间空间解析器,也就是下面要研究的TxNamespaceHandler :

代码语言:javascript
复制
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() {
		registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
		//annotation-driven解析器--->AnnotationDrivenBeanDefinitionParser
		registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
		registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
	}

}

AnnotationDrivenBeanDefinitionParser负责解析tx命名空间下的annotation-driven标签

BeanDefinitionParserDelegate的parseCustomElement负责解析非默认命名空间的标签:

代码语言:javascript
复制
	@Nullable
	public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
	//获取当前命令空间对应的URI,这里是http://www.springframework.org/schema/tx
		String namespaceUri = getNamespaceURI(ele);
		if (namespaceUri == null) {
			return null;
		}
		//根据上面这个URI去定位到对应的自定义命名空间解析器,怎么定位的呢?
		NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
		//如果没找到相关的解析器,那么就不管,但是会记录一个警告日志
		if (handler == null) {
			error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
			return null;
		}
		//调用自定义命名空间解析器的parse方法
		return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
	}

那是怎么根据一个URI定位到自定义命名空间解析器的呢?

resolve方法会通过解析URI定位到对应的自定义命名空间解析器

代码语言:javascript
复制
	public NamespaceHandler resolve(String namespaceUri) {
	//getHandlerMappings负责去查找所有可以发现的自定义命名空间解析器和namespaceUri的映射关系
	//第一次执行该方法时,返回的是URI和对应自定义命名空间解析器的全类名,此时解析器还没有被实例化
		Map<String, Object> handlerMappings = getHandlerMappings();
		//找到当前namespaceUri对应的自定义命令空间解析器---没找到就返回null,找到了就尝试去实例化
		Object handlerOrClassName = handlerMappings.get(namespaceUri);
		if (handlerOrClassName == null) {
			return null;
		}
        //如果是当前自定义解析器是第二次被查询,那么已经实例化了,直接返回		
		else if (handlerOrClassName instanceof NamespaceHandler) {
			return (NamespaceHandler) handlerOrClassName;
		}
		//如果当前解析器第一次被使用到,那么会进行实例化
		else {
			String className = (String) handlerOrClassName;
			try {
				Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
				if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
					throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
							"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
				}
				NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
				//调用实例化后的解析器的init方法
				namespaceHandler.init();
				//放入handlerMappings集合,这样下次来的时候,就直接返回实例化好的解析器即可
				handlerMappings.put(namespaceUri, namespaceHandler);
				return namespaceHandler;
			}
			catch (ClassNotFoundException ex) {
				throw new FatalBeanException("Could not find NamespaceHandler class [" + className +
						"] for namespace [" + namespaceUri + "]", ex);
			}
			catch (LinkageError err) {
				throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" +
						className + "] for namespace [" + namespaceUri + "]", err);
			}
		}
	}

还是那个问题: 如果获取到当前系统中可用的自定义解析器和对应URI的映射关系的呢?

这个就需要来看看getHandlerMappings的实现了:

代码语言:javascript
复制
	private Map<String, Object> getHandlerMappings() {
		Map<String, Object> handlerMappings = this.handlerMappings;
		//如果handlerMappings 不为空,说明不是第一次来了,那么直接返回
		//因为寻找当前系统中可用的自定义解析器和对应URI的映射关系,这个过程只需要执行一次即可
		if (handlerMappings == null) {
			synchronized (this) {
				handlerMappings = this.handlerMappings;
				if (handlerMappings == null) {
					if (logger.isTraceEnabled()) {
						logger.trace("Loading NamespaceHandler mappings from [" + this.handlerMappingsLocation + "]");
					}
					try {
					//handlerMappingsLocation就是META-INF/spring.handlers
						Properties mappings =
						//这里会去类路径下找所有的META-INF/spring.handlers文件,该文件中记录了解析器和URI的映射关系
								PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
						if (logger.isTraceEnabled()) {
							logger.trace("Loaded NamespaceHandler mappings: " + mappings);
						}
						handlerMappings = new ConcurrentHashMap<>(mappings.size());
						CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
						this.handlerMappings = handlerMappings;
					}
					catch (IOException ex) {
						throw new IllegalStateException(
								"Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
					}
				}
			}
		}
		return handlerMappings;
	}
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

这其实就是SPI思想,熟悉serviceLoader底层实现的小伙伴应该非常清楚,Drver驱动查找底层就是靠serviceLoader的服务发现机制(SPI)完成的

建议大家可以了解一下,可以看一下下面这篇文章

ServiceLoader和DriverManager的前世今生


查找到自定义命令空间解析器后,下一步就是就是调用解析器AnnotationDrivenBeanDefinitionParser的parse方法来解析自定义标签了

代码语言:javascript
复制
	public BeanDefinition parse(Element element, ParserContext parserContext) {
	   //注册一个TransactionalEventListenerFactory--用来生产事务事件监听器的工厂---会在事务提交,回滚等时间点,回调监听器相关接口--这里不多讲
		registerTransactionalEventListenerFactory(parserContext);
		String mode = element.getAttribute("mode");
		//判断代理模式
		//如果Mode为aspectj,那么走aspectj的代理
		if ("aspectj".equals(mode)) {
			// mode="aspectj"
			registerTransactionAspect(element, parserContext);
			if (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader())) {
				registerJtaTransactionAspect(element, parserContext);
			}
		}
		//其他情况都选择jdk或者cglib代理
		else {
			// mode="proxy"
			//下面就是准备自动代理创建器相关的东西了
			//AopAutoProxyConfigurer是AnnotationDrivenBeanDefinitionParser一个内部类
			AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
		}
		return null;
	}

AopAutoProxyConfigurer.configureAutoProxyCreator负责创建并配置自动代理创建器

AopAutoProxyConfigurer是AnnotationDrivenBeanDefinitionParser一个内部类,并且该类只有一个configureAutoProxyCreator方法

该方法主要就是来注册自动代理创建器,然后准备TransactionAttributeSource ,TransactionInterceptor和TransactionAttributeSourceAdvisor

代码语言:javascript
复制
		public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
		    //注册自动代理创建器,并解析标签中相关属性: proxyClass等,设置到自动代理创建器中
			AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
           //默认放入容器中的事务增强器的beanName为org.springframework.transaction.config.internalTransactionAdvisor
			String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
			//如果我们手动往容器中放入了与上面同名的增强器bean,那么这里就跳过,用户指定的优先级更高
			if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {
				Object eleSource = parserContext.extractSource(element);

				// Create the TransactionAttributeSource definition.
				//TransactionAttributeSource的bean定义准备
				//实际放入的是AnnotationTransactionAttributeSource--他会负责解析@Transactional注解,然后形成方法和TransactionAttribute的映射关系,进行保存
				RootBeanDefinition sourceDef = new RootBeanDefinition(
						"org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
				sourceDef.setSource(eleSource);
				//设置角色----ROLE_INFRASTRUCTURE---InfrastructureAdvisorAutoProxyCreator靠beanDefinition来过滤增强器
			//这里不是增强器,仅仅表明当前注入的bean是基础设置bean	 
				sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
				//registerWithGeneratedName会注册beanDefintion到注册中心,然后返回生成的beanName
				String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);

				// Create the TransactionInterceptor definition.
				//准备拦截器的bean定义
				RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
				interceptorDef.setSource(eleSource);
				//标注为基础设置bean
				interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
				//指定拦截器中事务管理器的beanName
				registerTransactionManager(element, interceptorDef);
				//指定拦截器中TransactionAttributeSource对应的beanName
				interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
				//注册拦截器的bean定义到注册中心,返回生成的拦截器beanName
				String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);

				// Create the TransactionAttributeSourceAdvisor definition.
				//增强器准备--增强器类型为BeanFactoryTransactionAttributeSourceAdvisor
				RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);
				advisorDef.setSource(eleSource);
				//标注为基础设置类--InfrastructureAdvisorAutoProxyCreator靠beanDefinition来过滤增强器
				advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
				//增强器需要transactionAttributeSource--因为内部的pointcut通过其来进行类级别和方法级别的过滤
				advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
				//指定advice--拦截器
				advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
				//是否指定了增强器的顺序--到时候aop过程中对筛选出来的增强器排序时会用到
				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);
			}
		}
	}

可以看出,上面的源码思路非常清晰,和我们进行模拟的过程是一样的思路:

  • 注册自动代理创建器
  • 是否要注册增强器—>用户是否已经注册过了beanName为org.springframework.transaction.config.internalTransactionAdvisor的增强器
  • 没有的话,先准备AnnotationTransactionAttributeSource
  • 再准备TransactionInterceptor ,将AnnotationTransactionAttributeSource设置给他,并且设置事务管理器
  • 最后就是TransactionAttributeSourceAdvisor,拦截器TransactionInterceptor 肯定要给他,其次就是transactionAttributeSource,负责初始化pointcut用的

如果看到这里,还对TransactionAttributeSource,TransactionAdvisor,TransactionInterceptor 不熟悉的,建议先回看之前的事务管理上和中

PropertyValues在populateBean进行属性注入时,会根据PropertyValue中保存的beanName或者字面值进行属性赋值

标签中的order属性指定的是自动生成的事务增强器的advisor的order属性值,用于在筛选完后的增强器集合中进行比较排序


registerTransactionManager–注册事务管理器给拦截器
代码语言:javascript
复制
	private static void registerTransactionManager(Element element, BeanDefinition def) {
		def.getPropertyValues().add("transactionManagerBeanName",
				TxNamespaceHandler.getTransactionManagerName(element));
	}

这里重点是事务管理器的beanName怎么得到的:

代码语言:javascript
复制
TxNamespaceHandler.getTransactionManagerName(element)

如果我们在标签中指定了transaction-manager属性对应的值,即TransactionManager在容器中的名字,那么就会采用我们指定的,否则会去容器中寻找名字默认为transactionManagerbeanName

代码语言:javascript
复制
	static String getTransactionManagerName(Element element) {
		return (element.hasAttribute(TRANSACTION_MANAGER_ATTRIBUTE) ?
				element.getAttribute(TRANSACTION_MANAGER_ATTRIBUTE) : DEFAULT_TRANSACTION_MANAGER_BEAN_NAME);
	}

AopNamespaceUtils.registerAutoProxyCreatorIfNecessary—注册自动代理创建器
代码语言:javascript
复制
	public static void registerAutoProxyCreatorIfNecessary(
			ParserContext parserContext, Element sourceElement) {
        //注册自动代理创建器,这里注册的就是InfrastructureAdvisorAutoProxyCreator			 
		BeanDefinition beanDefinition = AopConfigUtils.registerAutoProxyCreatorIfNecessary(
				parserContext.getRegistry(), parserContext.extractSource(sourceElement));
	    //从标签中读取出proxyClass属性,然后设置到自动代理创建器中,自动代理创建器都继承了ProxyConfig
	    //在创建代理对象的时候,ProxyFactory会拷贝当前自动代理创建器的ProxyConfig相关属性值
		useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
		//释放注册bean的事件
		registerComponentIfNecessary(beanDefinition, parserContext);
	}

AopConfigUtils的registerAutoProxyCreatorIfNecessary过程不清楚的看下面这篇文章,这里不分析

Spring读源码系列之AOP–05—aop常用工具类学习

useClassProxyingIfNecessary稍微看看:

代码语言:javascript
复制
	private static void useClassProxyingIfNecessary(BeanDefinitionRegistry registry, @Nullable Element sourceElement) {
		if (sourceElement != null) {
		//标签中是否设置了proxy-target-class值
			boolean proxyTargetClass = Boolean.parseBoolean(sourceElement.getAttribute(PROXY_TARGET_CLASS_ATTRIBUTE));
			//如果设置了就强迫自动代理创建器使用cglib来代理对象
			if (proxyTargetClass) {
				AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
			}
			//标签中是否设置了expose-proxy属性值,如果设置了,就强迫自动代理创建器在代理对象方法被拦截时,将代理对象暴露到当前线程中去
			boolean exposeProxy = Boolean.parseBoolean(sourceElement.getAttribute(EXPOSE_PROXY_ATTRIBUTE));
			if (exposeProxy) {
				AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
			}
		}
	}
代码语言:javascript
复制
	public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
	//我们已经注册过自动代理创建器了,现在注册中心一定是有对应bean定义的
		if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
			BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
			//增强一个propertyValue
			definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
		}
	}
   
   //思路同上
	public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
		if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
			BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
			definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
		}
	}

小结

代码语言:javascript
复制
 <tx:annotation-driven mode="proxy" proxy-target-class="true"/>

tx:annotation-driven标签方式开启事务支持的流程已经走完了,还剩下一些类没进行介绍,先别急,等先讲完注解一键开启事务支持的流程后,我统一来讲,剩下待讲类有:

  • AnnotationTransactionAttributeSource
  • BeanFactoryTransactionAttributeSourceAdvisor

@EnableTransactionManagement源码追踪

如果大家看过上篇文章的话,并理解了的话,下面就非常轻松了,如果没看过,强烈建议先看下:

Spring事务管理—中

和我们模拟时定义的注解一样:

代码语言:javascript
复制
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
//导入TransactionManagementConfigurationSelector
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
    //是否默认采用cglib进行代理
	boolean proxyTargetClass() default false;
    //代理默认
	AdviceMode mode() default AdviceMode.PROXY;
    //指定事务增强器的order大小
	int order() default Ordered.LOWEST_PRECEDENCE;

}

TransactionManagementConfigurationSelector—负责导入自动代理创建器和相关配置类

TransactionManagementConfigurationSelector是EnableTransactionManagement 导入的类,该类继承了AdviceModeImportSelector

selectImports方法返回的数组中每个元素都是一个待导入到IOC中的bean的全类名

代码语言:javascript
复制
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {

	@Override
	protected String[] selectImports(AdviceMode adviceMode) {
		switch (adviceMode) {
		//我们只看采用cglib和jdk动态代理的部分即可
			case PROXY:
				return new String[] {
                        //负责导入自动代理创建器--该类源码已经分析过了,不清楚的看Spring事务管理---中
                        AutoProxyRegistrar.class.getName(),
                        //配置类
						ProxyTransactionManagementConfiguration.class.getName()};
			case ASPECTJ:
				return new String[] {determineTransactionAspectClass()};
			default:
				return null;
		}
	}

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

}

因为AutoProxyRegistrar源码在模拟篇中已经详细分析过了,这里我只对ProxyTransactionManagementConfiguration进行分析


ProxyTransactionManagementConfiguration–负责

该类就是对拦截器,TransactionAttributeSource 和TransactionInterceptor 进行自动注入:

代码语言:javascript
复制
@Configuration(proxyBeanMethods = false) //采用lite模式--配置类不会被代理--可以提高节约资源,提高启动效率
//指定为基础bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
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();
		//设置transactionAttributeSource
		advisor.setTransactionAttributeSource(transactionAttributeSource);
		//设置transactionInterceptor
		advisor.setAdvice(transactionInterceptor);
		//是否需要设置增强器的order,enableTx来自父类,会从注解中读取order属性,判断是否被设置了 
		if (this.enableTx != null) {
			advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
		}
		return advisor;
	}

	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionAttributeSource transactionAttributeSource() {
		return new AnnotationTransactionAttributeSource();
	}

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

}

我们再来看看这个配置类的父类吧:

代码语言:javascript
复制
@Configuration
public abstract class AbstractTransactionManagementConfiguration implements ImportAware {

	@Nullable
	protected AnnotationAttributes enableTx;

	/**
	 * Default transaction manager, as configured through a {@link TransactionManagementConfigurer}.
	 */
	@Nullable
	protected TransactionManager txManager;

    //AnnotationMetadata封装着导入当前配置类的类上的注解集合的元数据信息
	@Override
	public void setImportMetadata(AnnotationMetadata importMetadata) {
		//拿到注解元数据集合中的EnableTransactionManagement注解的属性集合
		this.enableTx = AnnotationAttributes.fromMap(
				importMetadata.getAnnotationAttributes(EnableTransactionManagement.class.getName()));
		if (this.enableTx == null) {
			throw new IllegalArgumentException(
					"@EnableTransactionManagement is not present on importing class " + importMetadata.getClassName());
		}
	}

//TransactionManagementConfigurer中得到TransactionManager
//一般情况下这里也是没有的,springboot还没去看,但是应该会帮我们注册一个TransactionManager
//但是即使这里没有也没关系,因为事务拦截器发现自身没有设置TM时,会去找容器里面的TM
	@Autowired(required = false)
	void setConfigurers(Collection<TransactionManagementConfigurer> configurers) {
		//为空直接返回
		if (CollectionUtils.isEmpty(configurers)) {
			return;
		}
		//如果存在数量超过一个,则抛出异常
		if (configurers.size() > 1) {
			throw new IllegalStateException("Only one TransactionManagementConfigurer may exist");
		}
		//取出TransactionManagementConfigurer中的TransactionManager
		TransactionManagementConfigurer configurer = configurers.iterator().next();
		this.txManager = configurer.annotationDrivenTransactionManager();
	}


//参考xml自定义事务驱动标签解析过程:
//注册一个TransactionalEventListenerFactory--用来生产事务事件监听器的工厂---会在事务提交,回滚等时间点,回调监听器相关接口--这里不多讲
	@Bean(name = TransactionManagementConfigUtils.TRANSACTIONAL_EVENT_LISTENER_FACTORY_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public static TransactionalEventListenerFactory transactionalEventListenerFactory() {
		return new TransactionalEventListenerFactory();
	}

}

ImportAware接口的setImportMetadata方法

ImportAware接口如下:

代码语言:javascript
复制
public interface ImportAware extends Aware {
	void setImportMetadata(AnnotationMetadata importMetadata);
}

该接口只有一个方法,并且该方法会在ConfigurationClassPostProcessor的内部类ImportAwareBeanPostProcessor中被调用。

具体是在ImportAwareBeanPostProcessor的postProcessBeforeInitialization方法中调用

代码语言:javascript
复制
	private static class ImportAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

		private final BeanFactory beanFactory;

		public ImportAwareBeanPostProcessor(BeanFactory beanFactory) {
			this.beanFactory = beanFactory;
		}
        
        //postProcessProperties设置配置类的代理后IOC的注入问题--这里不展开 
		@Override
		public PropertyValues postProcessProperties(@Nullable PropertyValues pvs, Object bean, String beanName) {
			// Inject the BeanFactory before AutowiredAnnotationBeanPostProcessor's
			// postProcessProperties method attempts to autowire other configuration beans.
			if (bean instanceof EnhancedConfiguration) {
				((EnhancedConfiguration) bean).setBeanFactory(this.beanFactory);
			}
			return pvs;
		}

		@Override
		public Object postProcessBeforeInitialization(Object bean, String beanName) {
		//如果当前bean实现了ImportAware接口,就进行处理
			if (bean instanceof ImportAware) {
			//获取容器中的ImportRegistry注册中心
				ImportRegistry ir = this.beanFactory.getBean(IMPORT_REGISTRY_BEAN_NAME, ImportRegistry.class);
				AnnotationMetadata importingClass =
				 //如果当前bean实现了ImportAware接口,一般情况下该bean都是通过@Import注解导入的
				 //这里会找到是哪个类上标注了@Import注解,然后导入的该类,并拿到这个类上所有的注解元数据信息
				 ir.getImportingClassFor(ClassUtils.getUserClass(bean).getName());
				 //如果找到了,那么就调用当前类的setImportMetadata接口,否则就忽略不管
				if (importingClass != null) {
					((ImportAware) bean).setImportMetadata(importingClass);
				}
			}
			return bean;
		}
	}
在这里插入图片描述
在这里插入图片描述

TransactionManagementConfigurer
代码语言:javascript
复制
	@Autowired(required = false)
	void setConfigurers(Collection<TransactionManagementConfigurer> configurers) {
		if (CollectionUtils.isEmpty(configurers)) {
			return;
		}
		if (configurers.size() > 1) {
			throw new IllegalStateException("Only one TransactionManagementConfigurer may exist");
		}
		TransactionManagementConfigurer configurer = configurers.iterator().next();
		this.txManager = configurer.annotationDrivenTransactionManager();
	}

一般情况下TransactionManagementConfigurer在容器中是不存在的,因此transactionInterceptor关联的txManager 就为null

代码语言:javascript
复制
	@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;
	}

这样的话,事务拦截器在自己的invoke方法中,会去容器中寻找相关的TM,如果容器中还是没有,那就要报错了

事务拦截器工作流程不清楚的,看下面这篇文章

Spring事务管理—上


重点类讲解

上面已经介绍完了两种自动开启事务支持方式的工作原理,下面来看看这其中最关键的几个没讲的类,至于已经讲过的拦截器等,这里不会再重复讲了。

  • AnnotationTransactionAttributeSource
  • BeanFactoryTransactionAttributeSourceAdvisor

AnnotationTransactionAttributeSource

AnnotationTransactionAttributeSource继承了AbstractFallbackTransactionAttributeSource,这里先来看看其父类的源码实现:

代码语言:javascript
复制
public abstract class AbstractFallbackTransactionAttributeSource
		implements TransactionAttributeSource, EmbeddedValueResolverAware {

	/**
	 * 如果当前方法不需要TransactionAttribute,即不需要事务支持,那么缓存的时候用NULL_TRANSACTION_ATTRIBUTE来表示
	 * 避免重复检查
	 */
	@SuppressWarnings("serial")
	private static final TransactionAttribute NULL_TRANSACTION_ATTRIBUTE = new DefaultTransactionAttribute() {
		@Override
		public String toString() {
			return "null";
		}
	};

	protected final Log logger = LogFactory.getLog(getClass());

    //解析SPEL表达式等
	@Nullable
	private transient StringValueResolver embeddedValueResolver;

	/**
	 * 缓存
	 */
	private final Map<Object, TransactionAttribute> attributeCache = new ConcurrentHashMap<>(1024);

//EmbeddedValueResolverAware接口赐予的能力
	@Override
	public void setEmbeddedValueResolver(StringValueResolver resolver) {
		this.embeddedValueResolver = resolver;
	}


	/**
	 *获取当前方法对应的TransactionAttribute信息
	 */
	@Override
	@Nullable
	public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
	//忽略Object类
		if (method.getDeclaringClass() == Object.class) {
			return null;
		}

		//先查缓存
		//构造缓存key
		Object cacheKey = getCacheKey(method, targetClass);
		TransactionAttribute cached = this.attributeCache.get(cacheKey);
		if (cached != null) {
			//缓存中有,还需要判断是否是NULL_TRANSACTION_ATTRIBUTE
			//如果是说明当前方法不需要事务支持
			if (cached == NULL_TRANSACTION_ATTRIBUTE) {
				return null;
			}
			else {
				return cached;
			}
		}
		//缓存中没有
		else {
			//计算出当前方法对应的TransactionAttribute 
			TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
			// 如果为空,说明当前方法不需要事务支持
			if (txAttr == null) {
				this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
			}
			//有,那说明需要事务支持
			else {
			//methodIdentification是全类名.方法名
				String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
				if (txAttr instanceof DefaultTransactionAttribute) {
					DefaultTransactionAttribute dta = (DefaultTransactionAttribute) txAttr;
					//设置描述符
					dta.setDescriptor(methodIdentification);
					//设置解析属性时可能用到的字符串解析器
					dta.resolveAttributeStrings(this.embeddedValueResolver);
				}
				if (logger.isTraceEnabled()) {
					logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
				}
				//加入缓存
				this.attributeCache.put(cacheKey, txAttr);
			}
			return txAttr;
		}
	}


	protected Object getCacheKey(Method method, @Nullable Class<?> targetClass) {
		return new MethodClassKey(method, targetClass);
	}

    //获取当前方法对应的TransactionAttribute 
	@Nullable
	protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
		// 默认只给public方法提供事务支持
		//allowPublicMethodsOnly本类默认返回false,只能要重写,决定是否允许给非public方法提供事务支持
		if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
			return null;
		}

		//如果当前方法存在于一个接口上,那么我们需要该接口的实现类,并且如果targetClass是被cglib进行了代理,那么会获取该代理类的父类,然后从父类上获取到对应的method后返回
		Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);

		//判断方法上是否标注了@Transactional注解
		TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
		if (txAttr != null) {
			return txAttr;
		}

		//判断类上是否有注解
		txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
		if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
			return txAttr;
		}
        
        //如果specificMethod和method不一致,说明targetClass是被cglib代理过后的
		if (specificMethod != method) {
			// Fallback is to look at the original method.
			//去查看代理类的方法上是否有注解--因为可能是我们自己对目标类进行的代理
			txAttr = findTransactionAttribute(method);
			if (txAttr != null) {
				return txAttr;
			}
			// Last fallback is the class of the original method.
			//还是不行,再去检查代理类上是否存在注解
			txAttr = findTransactionAttribute(method.getDeclaringClass());
			if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
				return txAttr;
			}
		}
         //上面都检查完了,还是没找到,说明当前方法不需要事务支持
		return null;
	}


	/**
	 * Subclasses need to implement this to return the transaction attribute for the
	 * given class, if any.
	 * @param clazz the class to retrieve the attribute for
	 * @return all transaction attribute associated with this class, or {@code null} if none
	 */
	@Nullable
	protected abstract TransactionAttribute findTransactionAttribute(Class<?> clazz);

	/**
	 * Subclasses need to implement this to return the transaction attribute for the
	 * given method, if any.
	 * @param method the method to retrieve the attribute for
	 * @return all transaction attribute associated with this method, or {@code null} if none
	 */
	@Nullable
	protected abstract TransactionAttribute findTransactionAttribute(Method method);

	/**
	 * Should only public methods be allowed to have transactional semantics?
	 * <p>The default implementation returns {@code false}.
	 */
	protected boolean allowPublicMethodsOnly() {
		return false;
	}

}

再来看看子类的源码实现:

代码语言:javascript
复制
public class AnnotationTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource
		implements Serializable {

	private static final boolean jta12Present;

	private static final boolean ejb3Present;

	static {
		ClassLoader classLoader = AnnotationTransactionAttributeSource.class.getClassLoader();
		jta12Present = ClassUtils.isPresent("javax.transaction.Transactional", classLoader);
		ejb3Present = ClassUtils.isPresent("javax.ejb.TransactionAttribute", classLoader);
	}

	private final boolean publicMethodsOnly;
    
    //注解解析器集合
	private final Set<TransactionAnnotationParser> annotationParsers;

	public AnnotationTransactionAttributeSource() {
		this(true);
	}

	public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
		this.publicMethodsOnly = publicMethodsOnly;
		if (jta12Present || ejb3Present) {
			this.annotationParsers = new LinkedHashSet<>(4);
			this.annotationParsers.add(new SpringTransactionAnnotationParser());
			if (jta12Present) {
				this.annotationParsers.add(new JtaTransactionAnnotationParser());
			}
			if (ejb3Present) {
				this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
			}
		}
		else {
		//解析spring自家的@Transactional注解
			this.annotationParsers = Collections.singleton(new SpringTransactionAnnotationParser());
		}
	}


....


//当前类是否存在相关注解,即是否需要事务支持--增强器的pointcut会调用该方法进行类级别过滤
	@Override
	public boolean isCandidateClass(Class<?> targetClass) {
		for (TransactionAnnotationParser parser : this.annotationParsers) {
		//isCandidateClass当前类和当前类的方法上是否存在相关注解
			if (parser.isCandidateClass(targetClass)) {
				return true;
			}
		}
		return false;
	}

//判断当前类上存在注解吗,存在就解析为TransactionAttribute 返回
	@Override
	@Nullable
	protected TransactionAttribute findTransactionAttribute(Class<?> clazz) {
		return determineTransactionAttribute(clazz);
	}
//判断当前方法上存在注解吗,存在就解析为TransactionAttribute 返回
	@Override
	@Nullable
	protected TransactionAttribute findTransactionAttribute(Method method) {
		return determineTransactionAttribute(method);
	}

	/**
       利用注解解析器挨个解析,然后进行判断
	 */
	@Nullable
	protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
		for (TransactionAnnotationParser parser : this.annotationParsers) {
		//解析注解,如果解析成功就直接返回
			TransactionAttribute attr = parser.parseTransactionAnnotation(element);
			if (attr != null) {
				return attr;
			}
		}
		return null;
	}

	/**
	 * By default, only public methods can be made transactional.
	 * 默认只有public方法才能有事务支持
	 */
	@Override
	protected boolean allowPublicMethodsOnly() {
		return this.publicMethodsOnly;
	}

...

}

BeanFactoryTransactionAttributeSourceAdvisor

还是先看BeanFactoryTransactionAttributeSourceAdvisor的父类AbstractBeanFactoryPointcutAdvisor

代码语言:javascript
复制
public abstract class AbstractBeanFactoryPointcutAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware {

	@Nullable
	private String adviceBeanName;

	@Nullable
	private BeanFactory beanFactory;

	@Nullable
	private transient volatile Advice advice;

	private transient volatile Object adviceMonitor = new Object();

   ....
    //手动指定了advice
	public void setAdvice(Advice advice) {
		synchronized (this.adviceMonitor) {
			this.advice = advice;
		}
	}

	public void setAdviceBeanName(@Nullable String adviceBeanName) {
		this.adviceBeanName = adviceBeanName;
	}

//获取当前增强器内部的adivce
	@Override
	public Advice getAdvice() {
		Advice advice = this.advice;
		//如果手动指定了advice的话,这里直接返回
		if (advice != null) {
			return advice;
		}
       //如果没有手动指定的话,adviceBeanName和beanFactory必须都存在
       //adviceBeanName就是我们需要手动指定的了
		Assert.state(this.adviceBeanName != null, "'adviceBeanName' must be specified");
		Assert.state(this.beanFactory != null, "BeanFactory must be set to resolve 'adviceBeanName'");
       //会去容器中获取advice--这里为什么要加锁,感兴趣可以去深挖一下,不感兴趣的知道是从容器中获取advice即可
		if (this.beanFactory.isSingleton(this.adviceBeanName)) {
			// Rely on singleton semantics provided by the factory.
			advice = this.beanFactory.getBean(this.adviceBeanName, Advice.class);
			this.advice = advice;
			return advice;
		}
		else {
			// No singleton guarantees from the factory -> let's lock locally but
			// reuse the factory's singleton lock, just in case a lazy dependency
			// of our advice bean happens to trigger the singleton lock implicitly...
			synchronized (this.adviceMonitor) {
				advice = this.advice;
				if (advice == null) {
					advice = this.beanFactory.getBean(this.adviceBeanName, Advice.class);
					this.advice = advice;
				}
				return advice;
			}
		}
	}
....
}

再来看本类实现:

代码语言:javascript
复制
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {

	@Nullable
	private TransactionAttributeSource transactionAttributeSource;
    //TransactionAttributeSourcePointcut之前篇章讲过,这里不讲
	private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
		@Override
		@Nullable
		protected TransactionAttributeSource getTransactionAttributeSource() {
			return transactionAttributeSource;
		}
	};

    
	public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
		this.transactionAttributeSource = transactionAttributeSource;
	}

	public void setClassFilter(ClassFilter classFilter) {
		this.pointcut.setClassFilter(classFilter);
	}

	@Override
	public Pointcut getPointcut() {
		return this.pointcut;
	}

}

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-06-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Spring事务管理---下
  • 注解元数据驱动的声明式事务
    • tx:annotation-driven源码追踪
      • AnnotationDrivenBeanDefinitionParser负责解析tx命名空间下的annotation-driven标签
      • AopAutoProxyConfigurer.configureAutoProxyCreator负责创建并配置自动代理创建器
      • 小结
    • @EnableTransactionManagement源码追踪
      • TransactionManagementConfigurationSelector—负责导入自动代理创建器和相关配置类
      • ProxyTransactionManagementConfiguration–负责
  • 重点类讲解
    • AnnotationTransactionAttributeSource
      • BeanFactoryTransactionAttributeSourceAdvisor
      相关产品与服务
      容器服务
      腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档