前言
@EnableTransactionManagement
是Spring框架提供的一个注解,用于启用基于注解的事务管理。通过使用这个注解,你可以开启Spring对事务的自动管理功能,使得你可以在方法上使用 @Transactional
注解来声明事务。
@EnableTransactionManagement
主要有以下两个属性:
-
mode(默认为
AdviceMode.PROXY
):指定事务代理的模式。可以选择的值有AdviceMode.PROXY
和AdviceMode.ASPECTJ
。默认是AdviceMode.PROXY
,表示使用基于代理的方式实现事务管理。如果选择AdviceMode.ASPECTJ
,表示使用基于AspectJ的方式实现事务管理。 -
proxyTargetClass(默认为
false
):用于确定代理是否应该使用目标类的类代理,而不是目标类实现的接口。如果设置为true
,代理将使用目标类的类代理(CGLIB代理),如果设置为false
,代理将使用目标类实现的接口代理(JDK动态代理)。
当你在配置类上使用 @EnableTransactionManagement
注解时,Spring框架会自动扫描带有 @Transactional
注解的方法,并在这些方法周围织入事务管理的逻辑。如果一个带有 @Transactional
注解的方法执行过程中出现了异常,Spring会自动回滚事务。这个注解的作用是简化事务管理的配置和使用,提高开发效率。
示例:
@Configuration
@EnableTransactionManagement(mode = AdviceMode.PROXY, proxyTargetClass = false)
public class AppConfig {
// ...
}
在这个示例中,@EnableTransactionManagement
启用了基于代理的事务管理,使用了默认的代理模式和接口代理。你可以根据需要调整这两个属性的值。
源码分析
首先查看下@EnableTransactionManagement注解,使用@import注解导入了一个类:TransactionManagementConfigurationSelector
@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;
}
TransactionManagementConfigurationSelector
默认情况下mode = AdviceMode.PROXY,所以当配置类解析的时候会调用selectImports(AnnotationMetadata importingClassMetadata)方法。
也就是AdviceModeImportSelector类的selectImports(AnnotationMetadata importingClassMetadata)方法将被调用,继而调用TransactionManagementConfigurationSelector的selectImports(AdviceMode adviceMode)方法,此处涉及到ImportSelector的使用。
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
/**
* Returns {@link ProxyTransactionManagementConfiguration} or
* {@code AspectJ(Jta)TransactionManagementConfiguration} for {@code PROXY}
* and {@code ASPECTJ} values of {@link EnableTransactionManagement#mode()},
* respectively.
*/
@Override
protected String[] selectImports(AdviceMode adviceMode) {
// @EnableTransactionaManagement注解默认就是Proxy
switch (adviceMode) {
case PROXY:
// 然后就要把这个数组里的类进行加载,到此为止@EnableTransactionManagement注解的事情也就完成了
return new String[] {AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {determineTransactionAspectClass()};
default:
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);
}
}
selectImports(AdviceMode adviceMode)返回的String数组,也就是会把这个数组里的类转化为BeanDefinition并注册到容器中。
ConfigurationClassParser
类才是负责解析@Configuration注解的配置类。
ConfigurationClassBeanDefinitionReader
类是ConfigurationClassParser
的一个辅助类,用于将解析后的配置类信息转化为BeanDefinition对象并注册到Spring容器中。
ConfigurationClassParser
类的主要职责是扫描和解析带有@Configuration注解的配置类,它会解析类中的各种注解、方法和字段,以确定要创建和配置的bean。它处理@Configuration注解、@Bean注解、@ComponentScan注解、@Import注解等,并根据这些注解生成相应的BeanDefinition对象。一旦
ConfigurationClassParser
解析完成配置类,它会将解析得到的BeanDefinition对象传递给ConfigurationClassBeanDefinitionReader
,后者负责将这些BeanDefinition对象注册到Spring容器中。因此,
ConfigurationClassParser
和ConfigurationClassBeanDefinitionReader
两者共同工作,一个负责解析和处理@Configuration注解的配置类,另一个负责将解析结果转化为BeanDefinition并注册到容器中。
AutoProxyRegistrar
AutoProxyRegistrar类实现了ImportBeanDefinitionRegistrar接口,它的作用是在Spring容器中注册自动代理创建器(AutoProxyCreator)
具体来说,registerBeanDefinitions()方法是ImportBeanDefinitionRegistrar接口中的方法,它会在配置类(或使用)的初始化过程中被调用。该方法接收两个参数:
importingClassMetadata
:用于获取导入类的元数据,例如注解信息、类名等。registry
:用于注册BeanDefinition的BeanDefinitionRegistry对象。
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
private final Log logger = LogFactory.getLog(getClass());
@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;
}
}
}
}
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));
}
}
}
在registerBeanDefinitions()
方法中,首先通过importingClassMetadata
获取配置类上的所有注解类型。然后遍历这些注解类型,尝试获取注解上的mode
和proxyTargetClass
属性值。
如果找到了具有mode
和proxyTargetClass
属性的注解,并且它们的类型分别是AdviceMode
和boolean
,则表示找到了候选的自动代理创建器。根据mode
属性的值,如果是AdviceMode.PROXY
,则调用AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry)
方法注册自动代理创建器。
如果proxyTargetClass
属性为true
,则调用AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry)
方法,强制自动代理创建器使用类代理模式。然后,方法返回,完成注册过程。
如果在配置类上没有找到具有mode
和proxyTargetClass
属性的注解,或者出现了其他异常情况,会打印一条警告日志,提示可能没有按预期进行自动代理创建器的注册和配置。
总之,AutoProxyRegistrar
类的registerBeanDefinitions()
方法通过检查配置类上的注解,决定是否注册自动代理创建器,并根据注解的属性值进行相应的配置。这样可以实现自动代理的功能,用于对标注了特定注解的组件进行代理。
InfrastructureAdvisorAutoProxyCreator
首先AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);其实是将InfrastructureAdvisorAutoProxyCreator生产Bean的定义信息注册到容器中。但其实还会存在一个覆盖的行为,如下方法代码所示:
private static BeanDefinition registerOrEscalateApcAsRequired(
Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
// currentPriority 当前注入进来的class处于什么位置
//APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class); 0
//APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class); 1
//APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class); 2
// 也就是说底下的可以覆盖上面的
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
}
RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
return beanDefinition;
}
简要的分析一下registerOrEscalateApcAsRequired的实现。该方法用于在BeanDefinitionRegistry中注册自动代理创建器(AutoProxyCreator),并根据优先级进行必要的升级。
方法的主要逻辑如下:
-
首先,确保传入的
BeanDefinitionRegistry
参数不为null,否则抛出异常。 -
检查是否已经在
BeanDefinitionRegistry
中包含了名为AUTO_PROXY_CREATOR_BEAN_NAME
的BeanDefinition,其中AUTO_PROXY_CREATOR_BEAN_NAME
是自动代理创建器的名称。 -
如果已经存在自动代理创建器的BeanDefinition,则进一步判断当前要注册的自动代理创建器的类是否与已存在的BeanDefinition的类相同。如果不同,说明有更高优先级的自动代理创建器已经注册,需要进行升级。
-
通过比较自动代理创建器类的优先级,确定当前要注册的自动代理创建器的类是否具有更高的优先级。优先级通过
findPriorityForClass
方法进行判断。如果当前要注册的自动代理创建器的类优先级更高,则更新已存在的BeanDefinition的类为当前要注册的类。 -
如果不存在自动代理创建器的BeanDefinition,则创建一个
RootBeanDefinition
对象,该对象的类为当前要注册的自动代理创建器的类。 -
设置
RootBeanDefinition
的源对象为传入的source
参数,这个参数表示注册的来源。 -
为
RootBeanDefinition
设置属性值,将其顺序(order)设置为Ordered.HIGHEST_PRECEDENCE
,以确保它在其他Bean之前被创建。 -
将
RootBeanDefinition
的角色(role)设置为BeanDefinition.ROLE_INFRASTRUCTURE
,表示它是一个基础架构角色的Bean。 -
将
RootBeanDefinition
注册到BeanDefinitionRegistry
中,使用AUTO_PROXY_CREATOR_BEAN_NAME
作为Bean的名称。 -
最后,返回注册的
RootBeanDefinition
对象。
总之,这段代码描述了在BeanDefinitionRegistry中注册自动代理创建器的逻辑,并根据优先级进行必要的升级。它确保只注册具有最高优先级的自动代理创建器,并将其设置为基础架构角色的Bean。
然而在实际的使用过程中,都可能会被AnnotationAwareAspectJAutoProxyCreator替换,在同时开始了AOP和事务的情况下。具体可以看博主的另外一篇文章:SpringAOP源码解析之基础设施注册
ProxyTransactionManagementConfiguration
这个类 ProxyTransactionManagementConfiguration
是一个用于配置事务管理的Spring配置类。它继承自 AbstractTransactionManagementConfiguration
,并使用了 @Configuration
注解进行标记,表示这是一个配置类。
该类中定义了以下几个方法:
-
transactionAdvisor()
: 这个方法用于创建BeanFactoryTransactionAttributeSourceAdvisor
对象,作为事务的Advisor(通知器)。Advisor定义了在哪些切点上应用事务逻辑。该方法接收两个参数:transactionAttributeSource
(事务属性源)和transactionInterceptor
(事务拦截器)。它将这两个对象设置到创建的BeanFactoryTransactionAttributeSourceAdvisor
中,并根据需要设置Advisor的顺序。 -
transactionAttributeSource()
: 这个方法用于创建AnnotationTransactionAttributeSource
对象,作为管理事务属性的事务属性源。AnnotationTransactionAttributeSource
是一个基于注解的事务属性源,用于从标注了事务注解的方法获取事务属性信息。 -
transactionInterceptor()
: 这个方法用于创建TransactionInterceptor
对象,作为事务的拦截器。TransactionInterceptor
是一个AOP拦截器,用于在方法调用前后应用事务逻辑。它接收一个transactionAttributeSource
参数,用于获取事务属性信息。如果配置了txManager
(事务管理器),则将其设置到创建的TransactionInterceptor
中。
这些方法通过使用 @Bean
注解将它们声明为Bean,并使用 @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
注解指定它们的角色为基础设施角色。这意味着它们是框架内部使用的组件,用于支持事务管理功能。
在配置中,transactionAdvisor()
方法创建了一个事务Advisor,将事务属性源和事务拦截器组合在一起,用于对切点进行增强,从而实现事务管理。transactionAttributeSource()
方法创建了一个注解事务属性源,用于管理事务的属性信息。transactionInterceptor()
方法创建了一个事务拦截器,用于在方法执行前后应用事务逻辑。
通过使用这些方法创建相应的组件,并将它们注册为Spring容器中的Bean,可以实现对事务的管理和拦截。
这个类中的方法用于配置事务管理的相关组件,包括事务Advisor、事务属性源和事务拦截器。它们是支持Spring事务管理的关键组件,用于实现声明式事务的功能。
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
// 对切点进行增强,自然需要Advisor
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
// 实例化advisor对象
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
// 引入第二个bean
advisor.setTransactionAttributeSource(transactionAttributeSource);
// 引入第三个bean
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();
}
// Advisor需要的拦截器
@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;
}
}
InfrastructureAdvisorAutoProxyCreator和AnnotationAwareAspectJAutoProxyCreator
InfrastructureAdvisorAutoProxyCreator和AnnotationAwareAspectJAutoProxyCreator是Spring Framework中的两个关键类,用于实现AOP(面向切面编程)功能。
-
InfrastructureAdvisorAutoProxyCreator是Spring框架的一个基础设施类,用于自动创建代理对象来实现AOP。它是一个后置处理器,用于在Spring容器初始化过程中检测并自动创建适当的代理对象。它主要被用于支持基于XML配置的AOP功能。
-
AnnotationAwareAspectJAutoProxyCreator是Spring框架中的一个自动代理创建器,用于支持基于注解的AOP功能。它继承自InfrastructureAdvisorAutoProxyCreator,并在其基础上增加了对注解的解析和处理。它会扫描Spring容器中的bean,检测其中使用了AOP相关注解(例如@Aspect、@Before、@After等),然后自动创建相应的代理对象。
通过使用这两个类,Spring框架可以根据配置和注解信息,自动创建代理对象来实现AOP功能。AOP允许开发者通过定义切面(Aspect)和通知(Advice)来将横切关注点(Cross-cutting Concerns)应用到应用程序的不同部分,例如日志记录、性能监测、事务管理等。
在Spring框架中,默认情况下会注册一个InfrastructureAdvisorAutoProxyCreator(也称为AnnotationAwareAspectJAutoProxyCreator的父类)。这个类是Spring的一个基础设施类,用于支持的AOP功能。
当你使用@EnableAspectJAutoProxy注解时,Spring会自动将InfrastructureAdvisorAutoProxyCreator替换为更高级的AnnotationAwareAspectJAutoProxyCreator。AnnotationAwareAspectJAutoProxyCreator继承自InfrastructureAdvisorAutoProxyCreator,并在其基础上增加了对注解的解析和处理,以支持基于注解的AOP功能。
通过使用@EnableAspectJAutoProxy注解,你可以启用基于注解的AOP功能,并使用注解配置切面和通知,而不需要显式地在XML中配置AOP。也就是说当你使用@EnableAspectJAutoProxy注解时,Spring会自动升级为AnnotationAwareAspectJAutoProxyCreator,从而启用基于注解的AOP功能。
总结
本文描述的是@EnableTransactionManagement注解在初始化的时候做了哪些事情,其实和AOP还是有很大的关联。我们后续将针对事物的拦截、以及事物失效规则进行源码分析。