这才是Springboot事务创建流程的正确打开方式(附源码分析)

本文详细解析SpringBoot事务的创建流程,从自动加载配置开始,涉及InfrastructureAdvisorAutoProxyCreator、BeanFactoryTransactionAttributeSourceAdvisor等关键类,通过源码分析事务增强处理和代理类生成,帮助理解SpringBoot事务处理机制。
摘要由CSDN通过智能技术生成

SpringBoot事务

Springboot中事务是相对重要的一个部分。也是aop的一个使用场景。我们今天就来一起从源码的角度分析下,事务的整个创建过程。

关于springboot启动过程中的一些加载,很多都是通用的,这块就不再仔细讲述了。这部分可以参看spring boot 加载web容器tomcat流程源码分析和springboot整合mybatis源码分析这两篇文章

关于enhancer生成代理类的过程,可以参看Springboot中注解@Configuration源码分析

代码路径:springboot-transaction

1. 自动加载配置

首先还是读取org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration这个配置类,

方式还是通过springboot启动的时候自动加载配置文件spring-boot-autoconfigure-2.5.2.jar中\META-INF\spring.factories这个文件中key=org.springframework.boot.autoconfigure.EnableAutoConfiguration的值。其中就有org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration这个类。

在加载org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration时,会扫描加载内部类。

这里就会扫描到EnableTransactionManagementConfiguration这个内部类。


	@Configuration(proxyBeanMethods = false)
	@ConditionalOnBean(TransactionManager.class)
	@ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)
	public static class EnableTransactionManagementConfiguration {
		
		@Configuration(proxyBeanMethods = false)
		@EnableTransactionManagement(proxyTargetClass = false)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false")
		public static class JdkDynamicAutoProxyConfiguration {

		}

		@Configuration(proxyBeanMethods = false)
		@EnableTransactionManagement(proxyTargetClass = true)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
				matchIfMissing = true)
		public static class CglibAutoProxyConfiguration {

		}

	}

同时会扫描JdkDynamicAutoProxyConfiguration,CglibAutoProxyConfiguration这两个类,默认,我们在上下文中没有配置spring.aop.proxy-target-class属性,所以就只会加载CglibAutoProxyConfiguration这个类,继而读取@EnableTransactionManagement(proxyTargetClass = true)注解,继续去加载EnableTransactionManagement注解类上的import注解。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
//会读取这里的import注解,去加载TransactionManagementConfigurationSelector这个类
public @interface EnableTransactionManagement {
	......
}

我们看下这个TransactionManagementConfigurationSelector的继承关系

这才是Springboot事务创建流程的正确打开方式(附源码分析!)

可以看到TransactionManagementConfigurationSelector继承了AdviceModeImportSelector这个,间接实现了ImportSelector接口,所以在加载TransactionManagementConfigurationSelector时,会调用ImportSelector接口的这个方法String[] selectImports(AnnotationMetadata importingClassMetadata);这个接口,这个接口当前时在AdviceModeImportSelector这个类中实现的。

我们看看这部分代码

	//这个代码在AdviceModeImportSelector类中
	public final String[] selectImports(AnnotationMetadata importingClassMetadata) {
		Class<?> annType = GenericTypeResolver.resolveTypeArgument(getClass(), AdviceModeImportSelector.class);
        //这句代码是获取AdviceModeImportSelector子类的泛型参数。我们这里获取到的是EnableTransactionManagement
        
		Assert.state(annType != null, "Unresolvable type argument for AdviceModeImportSelector");

		AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
        //这句是从当前类的导入类中获取泛型参数注解的对象,这里获取到的是CglibAutoProxyConfiguration类上@EnableTransactionManagement(proxyTargetClass = true)注解的值
        
		if (attributes == null) {
			throw new IllegalArgumentException(String.format(
					"@%s is not present on importing class '%s' as expected",
					annType.getSimpleName(), importingClassMetadata.getClassName()));
		}

		AdviceMode adviceMode = attributes.getEnum(getAdviceModeAttributeName());
        //这个是获取model属性的值,这个属性有默认值EnableTransactionManagement注解mode的默认值是AdviceMode.PROXY
        
		String[] imports = selectImports(adviceMode);
        //这个代码的实现在TransactionManagementConfigurationSelector类中,这个也比较简单,就是根据adviceMode的值,返回要加载的类的类名,当前这里返回的是new String[] {AutoProxyRegistrar.class.getName(),						ProxyTransactionManagementConfiguration.class.getName()};
        //后面就会去加载AutoProxyRegistrar和ProxyTransactionManagementConfiguration这两个类
        
		if (imports == null) {
			throw new IllegalArgumentException("Unknown AdviceMode: " + adviceMode);
		}
		return imports;
	}

下面我们看看AutoProxyRegistrar和ProxyTransactionManagementConfiguration这两个类的加载

AutoProxyRegistrar实现了ImportBeanDefinitionRegistrar接口,加载时就会调用registerBeanDefinitions。

	//AutoProxyRegistrar的方法
	//这里的importingClassMetadata可以认为还是CglibAutoProxyConfiguration
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		boolean candidateFound = false;
		Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
        //这里是获取CglibAutoProxyConfiguration类上的注解
        
        //这里就比较简单了,依次获取CglibAutoProxyConfiguration类上的注解,查看属性mode和proxyTargetClass
		for (String annType : annTypes) {
			AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
			if (candidate == null) {
				continue;
			}
			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);
                    //这里就不进去了,这个会在registry中添加InfrastructureAdvisorAutoProxyCreator.class这个类的beanDefinition
                    
					if ((Boolean) proxyTargetClass) {
						AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
                        //这里是添加了属性("proxyTargetClass", Boolean.TRUE),最终生成的InfrastructureAdvisorAutoProxyCreator的属性进行设置
						return;
					}
				}
			}
		}
		......
	}

ProxyTransactionManagementConfiguration这个类是一个普通的Configuration配置类,在加载它的过程中同样会扫描到它里面的beanmethod进行加载,这里面的几个也都比较重要,我们看看它的源码

@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
//会扫描它内部的beanMethod,进行加载,关于这beanmethod的所用,这里就不展看说了,具体在讲解到事务执行流程的时候再说吧
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    //注意:这个方法的两个入参是后面两个beanmethod方法的bean对象
	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() {
		return new AnnotationTransactionAttributeSource();
	}

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

}

到这里,我们看看主要加载的bean都有哪些

  • InfrastructureAdvisorAutoProxyCreator,BeanFactoryTransactionAttributeSourceAdvisor主要是这两个TransactionAttributeSource,TransactionInterceptor这两个注入到了BeanFactoryTransactionAttributeSourceAdvisor这个对象中,就不单独说了,应该可以通过BeanFactoryTransactionAttributeSourceAdvisor这个bean对象获取到

2. InfrastructureAdvisorAutoProxyCreator类

我们看看InfrastructureAdvisorAutoProxyCreator的继承关系

这才是Springboot事务创建流程的正确打开方式(附源码分析!)

这个类的继承关系是比较复杂的,我们只挑选我们最关注的来分析吧。

从图上可以看到InfrastructureAdvisorAutoProxyCreator类间接实现了BeanPostProcessor接口,这个接口主要的所用是对每一个bean对象初始化前后做增强。在每一个bean初始化前调用postProcessBeforeInitialization,初始化后调用postProcessAfterInitialization。

注意:这里说的bean初始化前后并不是创建对象前后,这些操作肯定都是在创建对象之后

3.BeanFactoryTransactionAttributeSourceAdvisor类

我们现在看看BeanFactoryTransactionAttributeSourceAdvisor类,首先看下它的继承关系

这才是Springboot事务创建流程的正确打开方式(附源码分析!)

可以看到这个类也实现了Advisor接口,这个接口主要是用来承载Advice,而Advice主要是用来执行作为拦截器来使用的。

同时这个类也实现了PointcutAdvisor,可以返回Pointcut,可以用来筛选哪些方法需要拦截

4.判断bean对象是否需要进行事务增强处理

bean初始化后也会调用到InfrastructureAdvisorAutoProxyCreator.postProcessAfterInitialization方法(在AbstractAutoProxyCreator这个类中)。继而会调用到wrapIfNecessary这个方法。我们去看看这个方法

	//AbstractAutoProxyCreator类中的方法
	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;
		}

		// Create proxy if we have advice.
        //看上面的英文注释也能简单明白 aop就是在这里生成的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值