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