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

本文从源码角度详细分析了SpringBoot中事务的创建流程,包括自动加载配置、InfrastructureAdvisorAutoProxyCreator、BeanFactoryTransactionAttributeSourceAdvisor的作用,以及如何判断bean是否需要事务增强处理并生成代理类。
摘要由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 的继承关系

可以看到 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 的继承关系

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

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

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

3.BeanFactoryTransactionAttributeSourceAdvisor 类

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

可以看到这个类也实现了 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就是在这里生成的,对应事务其实也是用aop来完成的,我们重点看看这里的代码。        //我们的@Transactional注解是在UserServiceImpl这个类上,所以我们就只关注这个类的执行过程就可以了,我们进到这个方法里面去看看		Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);        //这个specificInterceptors主要是Advisor,这个不为空,说明当前的bean对象,可以被specificInterceptors来进行aop代理,就会进入里面的createProxy进行aop增强		if (specificInterceptors != DO_NOT_PROXY) {
  			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;	}

复制代码

@Override@Nullable//这个方法主要是根据我们传入的bean,查找适用的advice和advisor,如
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值