基于最新Spring 5.x,详细介绍了Spring 事务源码,包括@EnableTransactionManagement事务注解源码解析
上一篇文章:Spring 事务源码(2)—<tx:annotation-driven/>事务标签源码解析中我们讲解了
标签的解析源码,现在我们来看看用于替代该标签的注解@EnableTransactionManagement事务注解的源码解析。
Spring 5.x 源码汇总
Spring 事务源码(1)—<tx:advice/>事务标签源码解析
Spring 事务源码(2)—<tx:annotation-driven/>事务标签源码解析
Spring 事务源码(3)—@EnableTransactionManagement事务注解源码解析
Spring 事务源码(4)—BeanFactoryTransactionAttributeSourceAdvisor注解事务通知器源码解析
Spring 事务源码(5)—TransactionInterceptor事务拦截器与事务的AOP增强实现
Spring 事务源码(6)—createTransactionIfNecessary处理事务属性并尝试创建事务【两万字】
Spring 事务源码(7)—事务的completeTransactionAfterThrowing回滚、commitTransactionAfterReturning提交以及事务源码总结【一万字】
@EnableTransactionManagement注解用于替代
标签来开启声明式事务注解驱动!它是@Eenable开头的注解,这实际上就很简单了,我们在此前异步任务的源码:Spring @Async异步任务源码(1)—<task:annotation-driven/>、<task:executor/>、@EnableAsync解析的文章中@EnableAsync注解解析的部分就讲过,这样的注解的关键通常是内部的@Import元注解,@Import注解用于引入bean到容器中!
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
//核心注解
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
/**
* 指示是否创建基于子类(CGLIB)的代理,而不是标准的基于Java接口的代理(false)。默认为false,即基于Java接口。
* 仅当mode()设置为AdviceMode.PROXY时适用。
*/
boolean proxyTargetClass() default false;
/**
* 指示应该如何应用事务性通知。
*
* 默认为AdviceMode.PROXY,即基于Spring AOP动态代理。请注意,代理模式只允许通过代理拦截调用。
* 同一个类中的本地方法互相调用中,被调用方法上的事务注解将被忽略,因为Spring的拦截器不会在这样的运行时场景中发挥作用。
* 对于更高级的拦截模式,考虑将其切换到AdviceMode.ASPECTJ,即以及Aspect的静态织入
*/
AdviceMode mode() default AdviceMode.PROXY;
/**
* 指示在特定连接点应用多个通知时事务通知器的执行顺序。
*
* 默认为Ordered.LOWEST_PRECEDENCE
*/
int order() default Ordered.LOWEST_PRECEDENCE;
}
@Import注解引入的Class的类型不同,将会执行不同的解析流程,这一点我们在此前异步任务的源码中的@EnableAsync注解解析的部分也讲过了。@EnableTransactionManagement内部的@Import元注解指定的是TransactionManagementConfigurationSelector.class
,这个类是一个ImportSelectorBean
,因此我们直接看这个类的selectImports方法即可!
TransactionManagementConfigurationSelector还继承了AdviceModeImportSelector
,这是一个通用的基类,该基类及其实现类将会根据AdviceMode选择导入不同的注册的bean!这些特征说明TransactionManagementConfigurationSelector和@EnableAsync注解内部的@Import注解指定的AsyncConfigurationSelector.class属于同一体系。
通常情况下,selectImports方法将会返回org.springframework.context.annotation.AutoProxyRegistrar和org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration这两个class,即将会注册这两个bean定义到容器中。
/**
* 这是一个通用基类,用于根据AdviceMode来选择注册不同的bean定义,该基类被用于广泛的支持@Enable*注解
* 比如@EnableAsync、@EnableCaching、@EnableTransactionManagement(需要spring-tx依赖)
*
* @param 注解类型泛型
*/
public abstract class AdviceModeImportSelector<A extends Annotation> implements ImportSelector {
/**
* AdviceMode属性的默认属性名字为"mode"
*/
public static final String DEFAULT_ADVICE_MODE_ATTRIBUTE_NAME = "mode";
/**
* 获取AdviceMode属性的属性名,默认为"mode",子类可以覆盖重写
*/
protected String getAdviceModeAttributeName() {
return DEFAULT_ADVICE_MODE_ATTRIBUTE_NAME;
}
/**
* 该方法就是核心方法,在解析@Import注解时就会自动调用
*
* 该方法首先会校验指定的注解中是否存在类型为AdviceMode名字为getAdviceModeAttributeName()返回值的属性
* 然后会调用另一个selectImports(AdviceMode adviceMode)方法,该方法被子类重写,用于根据mode值判断应该使用哪些bean
*/
@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 adviceMode = attributes.getEnum(getAdviceModeAttributeName());
//调用selectImports(AdviceMode adviceMode)方法选择合适bean,该方法被子类重写
String[] imports = selectImports(adviceMode);
//不能为null
if (imports == null) {
throw new IllegalArgumentException("Unknown AdviceMode: " + adviceMode);
}
return imports;
}
/**
* 根据给定的AdviceMode确定应导入哪些类,该方法应被子类重写
*
* 返回null将会抛出IllegalArgumentException异常.
*/
@Nullable
protected abstract String[] selectImports(AdviceMode adviceMode);
}
/**
* 子类实现了AdviceModeImportSelector,泛型类型为@EnableTransactionManagement注解
* 重写了selectImports(AdviceMode adviceMode)方法
*/
public class TransactionManagementConfigurationSelector extends org.springframework.context.annotation.AdviceModeImportSelector<org.springframework.transaction.annotation.EnableTransactionManagement> {
/**
* 如果EnableAsync#mode是PROXY,那么返回AutoProxyRegistrar和ProxyTransactionManagementConfiguration
* 如果EnableAsync#mode是ASPECTJ,那么返回AspectJ(Jta)TransactionManagementConfiguration
*/
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
//一般都是PROXY,因此将会注册AutoProxyRegistrar和ProxyTransactionManagementConfiguration的bean定义,进行动态代理
return new String[]{AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
//支持Aspectj的静态代理织入
return new String[]{determineTransactionAspectClass()};
default:
//其他值则返回null,将会抛出异常
return null;
}
}
private String determineTransactionAspectClass() {
return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
}
}
AutoProxyRegistrar属于ImportBeanDefinitionRegistrar
类型,因此它本身实际上并不会注册到容器中,而是会调用它的registerBeanDefinitions方法,该方法中会尝试注册一个InfrastructureAdvisorAutoProxyCreator自动代理创建者,用于后续创建代理对象。
目前,只有@EnableCaching和@EnableTransactionManagement注解有可能自动引入AutoProxyRegistrar。因此在方法的第一参数将会传入具有@EnableCaching和@EnableTransactionManagement注解的类的元数据。
另外还会解析并设置自动代理创建者的proxyTargetClass属性。因此,如果引入类上有多个符合条件的自动代理注解(比如@EnableTransactionManagement、@EnableAsync、@EnableCaching、@EnableAspectJAutoProxy),并且有某个自动代理注解的proxyTargetClass属性设置为true,那么容器中的自动代理创建者的proxyTargetClass属性将会被设置为true,表示强制使用CGLIB代理。
/**
* AutoProxyRegistrar的方法
*
* 尝试为自动代理注册一个InfrastructureAdvisorAutoProxyCreator类型的自动代理创建者
* 并且会解析proxyTargetClass属性,如果有某个注解的proxyTargetClass属性设置为true
* 那么自动代理创建者的proxyTargetClass属性将会被设置为true,表示强制使用CGLIB代理。
*
* @param importingClassMetadata 引入该类的类的元数据。目前,只有@EnableCaching和@EnableTransactionManagement注解有可能引入该类
* 因此将会传入,具有@EnableCaching和@EnableTransactionManagement注解的类的元数据
* @param registry bean定义注册表
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean candidateFound = false;
//获取类上的所有注解类型
Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
//循环处理,对于具有mode和proxyTargetClass属性的注解统一处理
for (String annType : annTypes) {
//每一个注解的属性集合
AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
if (candidate == null) {
continue;
}
//获取mode属性
Object mode = candidate.get("mode");
//获取proxyTargetClass属性
Object proxyTargetClass = candidate.get("proxyTargetClass");
/*
* 如果存在这两个属性,并且类型也是匹配的
* 很多注解都有这两个属性,比如@EnableTransactionManagement、@EnableAsync、@EnableCaching、@EnableAspectJAutoProxy
*/
if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
Boolean.class == proxyTargetClass.getClass()) {
//
candidateFound = true;
//如果mode值是AdviceMode.PROXY值
if (mode == AdviceMode.PROXY) {
/*
* 调用AopConfigUtils.registerAutoProxyCreatorIfNecessary方法
* 尝试注册或者升级一个名为"org.springframework.aop.config.internalAutoProxyCreator"
* 类型为InfrastructureAdvisorAutoProxyCreator的自动代理创建者的bean定义
*/
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
/*
* 如果有某个注解的proxyTargetClass属性设置为true
* 那么自动代理创建者的proxyTargetClass属性将会被设置为true,表示强制使用CGLIB代理。
*/
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
if (!candidateFound && logger.isInfoEnabled()) {
String name = getClass().getSimpleName();
logger.info(String.format("%s was imported but no annotations were found " +
"having both 'mode' and 'proxyTargetClass' attributes of type " +
"AdviceMode and boolean respectively. This means that auto proxy " +
"creator registration and configuration may not have occurred as " +
"intended, and components may not be proxied as expected. Check to " +
"ensure that %s has been @Import'ed on the same class where these " +
"annotations are declared; otherwise remove the import of %s " +
"altogether.", name, name, name));
}
}
ProxyTransactionManagementConfiguration类是一个@Configuration配置类,将会通过内部的@Bean方法向容器注入一系列与AOP事务相关的一些基础bean定义,包括BeanFactoryTransactionAttributeSourceAdvisor事务通知器、AnnotationTransactionAttributeSource注解事务属性源、TransactionInterceptor事务拦截器、TransactionalEventListenerFactory事务事件监听器工厂
!
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
/**
* 注册一个事务通知器bean定义,名为"org.springframework.transaction.config.internalTransactionAdvisor"
* 类型就是BeanFactoryTransactionAttributeSourceAdvisor
*
* @param transactionAttributeSource 事务属性源
* @param transactionInterceptor 事务拦截器
*/
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
//创建BeanFactoryTransactionAttributeSourceAdvisor
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
//设置属性源
advisor.setTransactionAttributeSource(transactionAttributeSource);
//设置通知
advisor.setAdvice(transactionInterceptor);
//设置@EnableTransactionManagement注解的order属性
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
}
return advisor;
}
/**
* 注册一个事务属性源bean定义,名为"transactionAttributeSource"
* 类型就是AnnotationTransactionAttributeSource
*/
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
/**
* 注册一个事务拦截器bean定义,名为"transactionAttributeSource"
* 类型就是TransactionInterceptor
*
* @param transactionAttributeSource 事务属性源
*/
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource);
//设置事务管理器,这个事务管理器是指通过TransactionManagementConfigurer配置的,而不是通过bean定义的,一般为null
//所以说通过注解配置的TransactionInterceptor的transactionManager一般都为null,但是没关系,在使用时如果发现为null
//Spring会查找容器中的TransactionManager的实现来作为事务管理器
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
/**
* 父类AbstractTransactionManagementConfiguration
*/
@Configuration
public abstract class AbstractTransactionManagementConfiguration implements ImportAware {
@Nullable
protected AnnotationAttributes enableTx;
/**
* 通过TransactionManagementConfigurer配置的默认事务管理器,可以为null
*/
@Nullable
protected TransactionManager txManager;
/**
* 自动回调方法
* 用于获取@EnableTransactionManagement注解的属性
*
* @param importMetadata 引入当前类的类元数据,就是标注有@EnableTransactionManagement注解的类
*/
@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
//获取引入当前配置类的类上面的@EnableTransactionManagement注解的属性
this.enableTx = AnnotationAttributes.fromMap(
importMetadata.getAnnotationAttributes(EnableTransactionManagement.class.getName(), false));
//没有就抛出异常
if (this.enableTx == null) {
throw new IllegalArgumentException(
"@EnableTransactionManagement is not present on importing class " + importMetadata.getClassName());
}
}
/**
* 期望通过TransactionManagementConfigurer的方式注入事务管理器
* 由于@Autowired的required属性为false,没有TransactionManagementConfigurer的bean的时候,将不会执行该方法
*/
@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();
}
/**
* 注册一个事务事件监听器工厂的bean定义,名为"org.springframework.transaction.config.internalTransactionalEventListenerFactory"
* 类型就是TransactionalEventListenerFactory
*
* 该工厂可以将@TransactionalEventListener注解方法解析为一个ApplicationListenerMethodTransactionalAdapter类型的事件监听器,用于支持事务事件的监听。
*/
@Bean(name = TransactionManagementConfigUtils.TRANSACTIONAL_EVENT_LISTENER_FACTORY_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public static TransactionalEventListenerFactory transactionalEventListenerFactory() {
return new TransactionalEventListenerFactory();
}
}
@EnableTransactionManagement注解用于开启注解事务支持,也就是说如果配置了该注解,那么可以使用基于注解的声明式事务!
从源码中能看出,该标签会:
@EnableTransactionManagement注解
的关键在于内部的@Import
注解,该注解尝试向容器注入AutoProxyRegistrar和ProxyTransactionManagementConfiguration
两个bean。AutoProxyRegistrar
会尝试注册一个名为org.springframework.aop.config.internalAutoProxyCreator的InfrastructureAdvisorAutoProxyCreator类型的自动代理创建者的bean定义,该bean用于创建代理对象。
proxyTargetClass
属性。如果引入类上有多个符合条件的自动代理注解(比如@EnableTransactionManagement、@EnableAsync、@EnableCaching、@EnableAspectJAutoProxy),并且有某个自动代理注解的proxyTargetClass属性设置为true,那么容器中的自动代理创建者的proxyTargetClass属性将会被设置为true,表示强制使用CGLIB代理。ProxyTransactionManagementConfiguration
会尝试配置AOP事务相关的一些基础bean定义,包括BeanFactoryTransactionAttributeSourceAdvisor事务通知器、AnnotationTransactionAttributeSource注解事务属性源、TransactionInterceptor事务拦截器、TransactionalEventListenerFactory事务事件监听器工厂! 总体来说,源码比较简单!如果和前一篇文章Spring 事务源码(2)—<tx:annotation-driven/>事务标签源码解析的内容进行对比,我们发现它们所做的事都是差不多的,都会尝试注册那些基础bean,这些bean被用于后续Spring 事务的处理逻辑中,我们后面会一一讲到。因此,我们可以说,@EnableTransactionManagement可用于替代<tx:annotation-driven/>标签。
相关文章:
https://spring.io/
Spring Framework 5.x 学习
Spring Framework 5.x 源码
如有需要交流,或者文章有误,请直接留言。另外希望点赞、收藏、关注,我将不间断更新各种Java学习博客!