Spring 源码阅读 73:@EnableTransactionManagement 分析
基于 Spring Framework v5.2.6.RELEASE
概述
开发 Spring 应用时,通过在配置类上添加 @EnableTransactionManagement 注解,可以开启开启注解驱动的事务管理能力,被 @Transactional 注解标注的类或者方法,将会在一个数据库事务中执行。
本文将从 @EnableTransactionManagement 注解的源码出发,分析它是如何开启事务管理的。
EnableTransactionManagement 分析
进入 EnableTransactionManagement 的源码。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
@EnableTransactionManagement 注解包含三个属性。
proxyTargetClass 属性
proxyTargetClass属性表示是否强制采用 CGLIB 的方式来创建代理对象。在 Spring 中,事务管理是通过 AOP 特性来实现的,而 AOP 是通过对 Bean 的代理来实现的,包括 JDK 动态代理和 CGLIB 代理,默认情况下 Spring 会优先采用 JDK 动态代理的方式,在无法采用 JDK 动态代理的时候,则采用 CGLIB 的方式。
默认情况下,proxyTargetClass的值为false,如果将其配置为true,则所有的代理对象都会通过 CGLIB 的方式来创建。
值得注意的是,如果这里将proxyTargetClass配置为true,那么,不仅被标记了 @Transactional 注解的类以及其标记的方法所在的类会被强制采用 CGLIB 创建代理对象,Spring 容器中所有需要创建代理的 Bean 都会被强制采用 CGLIB 的方式来创建代理。
mode 属性
mode的值是一个 AdviceMode 类型的枚举,默认值是AdviceMode.PROXY。它表示只能通过代理模式执行拦截的逻辑,这是通常情况下会采用的值。
order 属性
order属性表示事务相关的增强的顺序,默认是Ordered.LOWEST_PRECEDENCE,也就是最小值。
TransactionManagementConfigurationSelector 分析
除了以上三个配置属性外,@EnableTransactionManagement 通过 @Import 元注解,倒入了配置类型 TransactionManagementConfigurationSelector。
先看它的继承关系。

它是一个 ImportSelector 的实现类,先介绍一下实现了 ImportSelector 的类型,是如何在 Spring 的配置中起作用的。
当 Spring 扫描到应用中的某个配置类上被标记了 @EnableTransactionManagement 注解时,会通过它的 @Import 元注解找到其导入的类型 TransactionManagementConfigurationSelector,然后,判断出它是 ImportSelector 的实现类,就会调用它的selectImports方法,执行其中的配置逻辑。
此处被调用的是参数类型为 AnnotationMetadata 的selectImports方法,被调用时传入的参数封装了 @EnableTransactionManagement 注解的元信息。但是,TransactionManagementConfigurationSelector 并没有实现这个方法,因此,它继承了父类 AdviceModeImportSelector 中该方法的实现。
// org.springframework.context.annotation.AdviceModeImportSelector#selectImports(org.springframework.core.type.AnnotationMetadata)
@Override
public final String[] selectImports(AnnotationMetadata importingClassMetadata) {
Class<?> annType = GenericTypeResolver.resolveTypeArgument(getClass(), AdviceModeImportSelector.class);
Assert.state(annType != null, "Unresolvable type argument for AdviceModeImportSelector");
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
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());
String[] imports = selectImports(adviceMode);
if (imports == null) {
throw new IllegalArgumentException("Unknown AdviceMode: " + adviceMode);
}
return imports;
}
其中比较核心的逻辑就是从注解元信息中,获取到mode属性的值,然后将其作为参数调用了另外一个selectImports方法,这是一个模版方法,可以在 TransactionManagementConfigurationSelector 中找到方法的实现。
// org.springframework.transaction.annotation.TransactionManagementConfigurationSelector#selectImports
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return new String[] {AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {determineTransactionAspectClass()};
default:
return null;
}
}
在默认情况下,也就是switch语句的PROXY分支,会返回 AutoProxyRegistrar 和 ProxyTransactionManagementConfiguration 的类名称。
前面交代了,这个方法是在 Spring 扫描和处理配置类的时候被调用的,当返回这两个类名称后,Spring 会再解析这里两个类。
接下来我们再分别来看这两个类。
AutoProxyRegistrar 分析
AutoProxyRegistrar 实现了 ImportBeanDefinitionRegistrar 接口,因此,当 Spring 加载到它之后,会执行其中的registerBeanDefinitions方法,执行一些注册 BeanDefinition 的逻辑。
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean candidateFound = false;
Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
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);
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
// 此处省略 LOG 代码
}
这个方法中,依然可以获取到 @EnableTransactionManagement 的注解元数据,通过从中获取mode和proxyTargetClass属性的值,执行后续的操作。
当mode的值是AdviceMode.PROXY的时候,会执行 AopConfigUtils 的registerAutoProxyCreatorIfNecessary方法。从这个方法名可以看出,它的作用是创建用于给 Bean 创建代理对象的后处理器,因为 Spring 中的事务管理是依赖 AOP 特性的,因此,开启事务管理之前要先确保开启的 AOP 功能。
如果proxyTargetClass的值是true的话,还会再额外执行 AopConfigUtils 的forceAutoProxyCreatorToUseClassProxying方法,它的作用是找到 Spring 容器中用来创建 AOP 代理对象的后处理器的 BeanDefinition,并为其添加proxyTargetClass属性,值为true,这样,在为 Bean 实例创建代理对象时,就会直接采用 CGLIB 的方式。
总结,AutoProxyRegistrar 中的配置逻辑,其实就是为了确保 Spring 在开启事务管理之前,开启了 AOP 特性。
ProxyTransactionManagementConfiguration 分析
ProxyTransactionManagementConfiguration 是一个标记了 @Configuration 注解的配置类,Spring 解析它的时候,会获取到 @Bean 标记的方法,并在容器中注册对应的 BeanDefinition。
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
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 方法,注册了三个 Bean,其中 BeanFactoryTransactionAttributeSourceAdvisor 依赖另外两者,也是三者中扮演重要角色的一个。从它的名字就可以看出,它是一个 Advisor 实现类,也意味着事务管理的相关增强逻辑、增强逻辑与类和方法的匹配,都是通过它来执行的。
AbstractTransactionManagementConfiguration 分析
除此之外,ProxyTransactionManagementConfiguration 的父类 AbstractTransactionManagementConfiguration 同样是一个 @Configuration 注解标记的配置类,其中有两个配置相关的方法。
@Autowired(required = false)
void setConfigurers(Collection<TransactionManagementConfigurer> configurers) {
if (CollectionUtils.isEmpty(configurers)) {
return;
}
if (configurers.size() > 1) {
throw new IllegalStateException("Only one TransactionManagementConfigurer may exist");
}
TransactionManagementConfigurer configurer = configurers.iterator().next();
this.txManager = configurer.annotationDrivenTransactionManager();
}
setConfigurers方法是一个被标记了 @Autowired 注解的方法,参数重传入了 TransactionManagementConfigurer 类型的集合configurers。在方法体中,如果集合为空,则不做任何处理,如果集合元素数大于 1,则抛出异常,最后,调用集合中唯一的元素的annotationDrivenTransactionManager方法,得到一个 TransactionManager 对象, 赋值给成员变量txManager。
从上述的逻辑中可以看出,这个方法用来加载 TransactionManager 配置。因此,我们可以创建一个类,通过实现 TransactionManagementConfigurer 接口及其 annotationDrivenTransactionManager 方法,来通过代码配置 TransactionManager。只需将这个类型作为一个 Bean 注册到 Spring 容器中,即可在此处被加载到。
@Bean(name = TransactionManagementConfigUtils.TRANSACTIONAL_EVENT_LISTENER_FACTORY_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public static TransactionalEventListenerFactory transactionalEventListenerFactory() {
return new TransactionalEventListenerFactory();
}
最后,还通过 @Bean 方法的方式,注册了一个 TransactionalEventListenerFactory 类型的 Bean。
总结
到这里,我们就知道了 @EnableTransactionManagement 是如何开启事务管理的。首先,它提供了几个配置属性,并引入了 TransactionManagementConfigurationSelector 配置类;然后,在 TransactionManagementConfigurationSelector 中,又引入了 AutoProxyRegistrar 和 ProxyTransactionManagementConfiguration,它们两者的作用是确保 Spring 已经开启了 AOP 特性以及向容器中注册用于处理事务管理的 Advisor。
转载自:https://juejin.cn/post/7165517193684189198