Spring事务源码阅读(注解式和xml配置式)

本文详细探讨了Spring框架中事务管理的实现,从BeanFactoryTransactionAttributeSourceAdvisor、TransactionAttributeSource到TransactionInterceptor,分析了注解式和XML配置式的事务管理流程。文章介绍了事务管理入口,如TransactionManagementConfigurationSelector、AutoProxyRegistrar和ProxyTransactionManagementConfiguration,以及事务拦截器TransactionInterceptor的工作原理。此外,还讲解了事务拦截器如何生成代理,以及TransactionInfo、TransactionAttribute和TransactionStatus等关键类的作用。
摘要由CSDN通过智能技术生成

本文参考:《Spring源码深度解析》及源码走读.培养源码阅读思想

文章目录


先放图,du害一下大家, 在这里插入图片描述
在这里插入图片描述

1.必须懂的几个类

试想一下,如果Connection支持事务提交回滚(底层支持),那么你如何来设计你的事务处理框架?
我相信很多人的想法都是

  • 先读取 @Transation注解的属性.生成一个对象(存放事务相关)
  • 根据得到的该对象进行事务的commit,失败回滚,最终事务清除.

Spring框架对事务的支持大概也是这样的步骤,Spring支持嵌入事务,即方法中嵌套方法,如果都支持事务,则在里面的事务结束或者失败之后,外面的事务继续执行.
我们刚才提到 @Transation注解的属性提取,那么必定需要这样一个类去做提取的操作,提取的对象存储也需要一个相应类,用什么方式执行事务,这些都是我们后面需要讨论的内容,但是,在此之前,我们先看几个类,我们已经知道了实现事务的大概步骤,那么我们需要来看一下,Spring怎么去实现这些步骤的.

2.1 提取器驱动(装载)的advisor:BeanFactoryTransactionAttributeSourceAdvisor

我们知道Spring框架大量的使用了接口,可以想象,对于 @Transation注解的提取,Spring必定也是通过接口的实现类来定义提取方法(下一个会讲到),所以我们可以想象,我们需要一个类来承接这些接口和其他的属性.我们这里要讲的就是这个类。
我们看一下类上的注解:

  • Advisor driven by a TransactionAttributeSource, used to include a transaction advice bean for methods that are transactional.

包含一个 TransactionAttributeSource,用于事务通知。我们暂且不管 TransactionAttributeSource类的作用,目前我们可以知道的就是BeanFactoryTransactionAttributeSourceAdvisor他会装载和提供一个 TransactionAttributeSource类。
我们看他是怎么实现 TransactionAttributeSource的。

@SuppressWarnings("serial")
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
   
	
	//这个就是我们念念不忘的TransactionAttributeSource
	private TransactionAttributeSource transactionAttributeSource;

    //因为BeanFactoryTransactionAttributeSourceAdvisor 继承了PointCut接口,所以需要实现getPointCut方法
    //而获取到的PointCut类会返回我们需要的TransactionAttributeSource。
	private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
   
		@Override
		protected TransactionAttributeSource getTransactionAttributeSource() {
   
			return transactionAttributeSource;
		}
	};
	
	@Override
	public Pointcut getPointcut() {
   
		return this.pointcut;
	}
}

很容易我们看到了TransactionAttributeSource 这个类,并且因为BeanFactoryTransactionAttributeSourceAdvisor继承了Pointcut接口,需要实现getPointcut方法,相当于是
通过得到PointCut实现类,再获取TransactionAttributeSource

2.2 @Transation注解元数据提取器:TransactionAttributeSource

@Transation的提取需要一定的规则,而不同的方式可能对应不同的规则,所以Spring利用接口的方式,制定提取的抽象。通过继承实现不同的提取规则。
首先你要知道 TransactionAttributeSource是一个接口,我们看一下类的描述

  • Strategy interface used by TransactionInterceptor for metadata retrieval.
    Implementations know how to source transaction attributes, whether from configuration, metadata attributes at source level (such as Java 5 annotations), or anywhere else.

提供给TransactionInterceptor拦截器用于事务元数据提取的接口.
但是接口需要实现类,因为是注解解析,这边的具体实现类是 AnnotationTransactionAttributeSource
作为一个注解提取器, AnnotationTransactionAttributeSource如何实现提取呢?

3.1 真实注解处理器:TransactionAnnotationParser

这边就给你答案,那就是TransactionAnnotationParser,看到该类的构造方法.必定会注入SpringTransactionAnnotationParser,这个类,这也是我们后面处理注解需要注意的。

	public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
   
		this.publicMethodsOnly = publicMethodsOnly;
		this.annotationParsers = new LinkedHashSet<TransactionAnnotationParser>(2);
		this.annotationParsers.add(new SpringTransactionAnnotationParser());
		if (jta12Present) {
   
			this.annotationParsers.add(new JtaTransactionAnnotationParser());
		}
		if (ejb3Present) {
   
			this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
		}
	}

2.3 事务执行器\拦截器:TransactionInterceptor

首先知道一点就是 ****实现了 MethodInterceptor接口,需要实现这个类的 invoke方法,事务处理的具体逻辑就在这里,而 MethodInterceptor又会在代理创建的时候被调用,所以我们基本知道该拦截器实现事务管理是通过invoke方法在代理的时候实现。
我们在后面的描述中会讲到具体实现,别着急
关注一下类上的注释:

  • AOP Alliance MethodInterceptor for declarative transaction management using the common Spring transaction infrastructure (PlatformTransactionManager)
  • TransactionInterceptors are thread-safe.

事务管理线程安全

2. 事务管理入口

2.1 注解式

还记得开启事务的注解式什么吗?我错,我知道你不记得了。
开启事务的注解是 EnableTransactionManagement,我们可以查看一下这个注解的使用,

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
   
	boolean proxyTargetClass() default false;
	
	//实现事务的方式(proxy或者aspectj)
	AdviceMode mode() default AdviceMode.PROXY;
	
	int order() default Ordered.LOWEST_PRECEDENCE;
}

很好,我们看到这个注解有一个mode,能够配置事务管理实现的方式,默认是PROXY.
在注解上面有一个 @Import注解,如果你告诉我不懂,我就是一巴掌过去. @Import注解引入一个Selector类,我们要看一下他是做什么幺蛾子的。

3.1 事务管理选择器:TransactionManagementConfigurationSelector

这个注解继承了AdviceModeImportSelector,实现selectImport方法,朔本回源,在Mvc启动的时候会调用Selector,也就是这样启动的.这边我们不细究,知道一个大概:

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
   
	@Override
	protected String[] selectImports(AdviceMode adviceMode) {
   
		switch (adviceMode) {
   
			case PROXY:
				return new String[] {
   AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
			case ASPECTJ:
				return new String[] {
   TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
			default:
				return null;
		}
	}
}

这里看到了AdviceMode 的选择,我们只分析PROXY的方式,不要问为什么,问就是我菜.
PROXY的方式会返回两个类:AutoProxyRegistrar
ProxyTransactionManagementConfiguration

幺蛾子就出在这里面.

4.1 注册代理构造器:AutoProxyRegistrar

这个类只有一个方法,这个方法会去注册一些BeanDefinition.

@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
   
		boolean candidateFound = false;
		Set<String> annoTypes = importingClassMetadata.getAnnotationTypes();
		for (String annoType : annoTypes) {
   
			AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);
			Object mode = candidate.get("mode");
			Object proxyTargetClass = candidate.get("proxyTargetClass");
			if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
					Boolean.class == proxyTargetClass.getClass()) {
   
				candidateFound = true;
				if (mode == AdviceMode.PROXY) {
   
					//重要的地方我只看到这里
					AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
					if ((Boolean) proxyTargetClass) {
   
						AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
						return;
					}
				}
			}
		}
	}

虽然这个类叽里呱啦的说了一堆,但是重要的是这一行代码,这个方法会为我们注册一个很重要的类:InfrastructureAdvisorAutoProxyCreator,自动代理构造器,我们对于advisor的查找和代理的实现都在这个类中实现,后面我们会说道。

	AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);

	public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
   
		return registerAutoProxyCreatorIfNecessary(registry, null);
	}

	public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
   
		return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
	}
4.2 事务注解驱动配置:ProxyTransactionManagementConfiguration

这个类,会为我们注册几个Bean,就是我们一开头说的,事务注解元数据提取器事务处理拦截器提取器承载类

@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
   

	//事务注解提取器的承载类
	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
   
		BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
		//注入事务注解提取器
		advisor.setTransactionAttributeSource(transactionAttributeSource());
		//注入拦截器
		advisor.setAdvice(transactionInterceptor());
		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() {
   
		TransactionInterceptor interceptor = new TransactionInterceptor();
		//注入事务注解提取器
		interceptor.setTransactionAttributeSource(transactionAttributeSource());
		if (this.txManager != null) {
   
			//事务管理器:PlatformTransactionManager
			interceptor.setTransactionManager(this.txManager);
		}
		return interceptor;
	}

}

2.2 XML式

3.1 事务命名空间处理器:TxNamespaceHandler

这个类实现了NameSpaceHandler,Spring框架会实现NamespaceHandler接口实现类的调用,这个我们暂时不管他。
可以想象到,和注解处理的方式应该类似,这边也应该注入,我们刚才讲的三个类.所以我们来看一下代码实现

	@Override
	public void init() {
   
		registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
		registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
		registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
	}

这边注册了三个BeanDefinitionParser的类,用屁股想象都知道,他大概想要去做什么事情,但是我们还是一个一个来看一下.

4.1 TxAdviceBeanDefinitionParser:注册事务注解提取器(或直接读取事务配置)

看到这边会去提取xml的元素,然后判断是否手动在XML中写入了事务相关属性,parseAttributeSource这个方法会去解析相关的属性(只读、超时时间…)
如果不是xml方式去注入的话,就需要去注册一个AnnotationTransactionAttributeSource,让这个类去提取**@Transational**上的属性,然后生成对应类.

	@Override
	protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
   
		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) {
   
			// 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"));
		}
	}
4.2 注册事务基础Bean配置

等下我们看代码的时候你会发现,他实现了和事务注解驱动配置:ProxyTransactionManagementConfiguration类似的功能:

	@Override
	public BeanDefinition parse(Element element, ParserContext parserContext) {
   
		registerTransactionalEventListenerFactory(parserContext);
		String mode = element.getAttribute("mode");
		if ("aspectj".equals(mode)) {
   
			// mode="aspectj"
			registerTransactionAspect(element, parserContext);
		}
		else {
   
			// mode="proxy"
			AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
		}
		return null;
	}

这边我们依然只看PROXY的方式,我们可以看到下面的代码基本可以分成四步:

  • AopNamespaceUtils.registerAutoProxyCreatorIfNecessary:注册InfrastructureAdvisorAutoProxyCreator以及xml配置的解析,不具体看了
  • 注入AnnotationTransactionAttributeSource
  • 注入TransactionInterceptor
  • 注入BeanFactoryTransactionAttributeSourceAdvisor
  • 注册上述的组件到context
public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
   
			//注册InfrastructureAdvisorAutoProxyCreator类和解析XML属性
			AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);

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

				//注入AnnotationTransactionAttributeSource
				RootBeanDefinition sourceDef = new RootBeanDefinition(
						"org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
				sourceDef.setSource(eleSource);
				sourceDef.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

了-凡

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值