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,如