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就是在这里生成的