Spring事务之@EnableTransactionManagement

前言

@EnableTransactionManagement 是Spring框架提供的一个注解,用于启用基于注解的事务管理。通过使用这个注解,你可以开启Spring对事务的自动管理功能,使得你可以在方法上使用 @Transactional 注解来声明事务。

@EnableTransactionManagement 主要有以下两个属性:

  1. mode(默认为 AdviceMode.PROXY):指定事务代理的模式。可以选择的值有 AdviceMode.PROXYAdviceMode.ASPECTJ。默认是 AdviceMode.PROXY,表示使用基于代理的方式实现事务管理。如果选择 AdviceMode.ASPECTJ,表示使用基于AspectJ的方式实现事务管理。

  2. 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)方法。

Spring事务之@EnableTransactionManagement_第1张图片

也就是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容器中。

因此,ConfigurationClassParserConfigurationClassBeanDefinitionReader两者共同工作,一个负责解析和处理@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获取配置类上的所有注解类型。然后遍历这些注解类型,尝试获取注解上的modeproxyTargetClass属性值。

如果找到了具有modeproxyTargetClass属性的注解,并且它们的类型分别是AdviceModeboolean,则表示找到了候选的自动代理创建器。根据mode属性的值,如果是AdviceMode.PROXY,则调用AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry)方法注册自动代理创建器。

如果proxyTargetClass属性为true,则调用AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry)方法,强制自动代理创建器使用类代理模式。然后,方法返回,完成注册过程。

如果在配置类上没有找到具有modeproxyTargetClass属性的注解,或者出现了其他异常情况,会打印一条警告日志,提示可能没有按预期进行自动代理创建器的注册和配置。

总之,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),并根据优先级进行必要的升级。

方法的主要逻辑如下:

  1. 首先,确保传入的 BeanDefinitionRegistry 参数不为null,否则抛出异常。

  2. 检查是否已经在 BeanDefinitionRegistry 中包含了名为 AUTO_PROXY_CREATOR_BEAN_NAME 的BeanDefinition,其中 AUTO_PROXY_CREATOR_BEAN_NAME 是自动代理创建器的名称。

  3. 如果已经存在自动代理创建器的BeanDefinition,则进一步判断当前要注册的自动代理创建器的类是否与已存在的BeanDefinition的类相同。如果不同,说明有更高优先级的自动代理创建器已经注册,需要进行升级。

  4. 通过比较自动代理创建器类的优先级,确定当前要注册的自动代理创建器的类是否具有更高的优先级。优先级通过 findPriorityForClass 方法进行判断。如果当前要注册的自动代理创建器的类优先级更高,则更新已存在的BeanDefinition的类为当前要注册的类。

  5. 如果不存在自动代理创建器的BeanDefinition,则创建一个 RootBeanDefinition 对象,该对象的类为当前要注册的自动代理创建器的类。

  6. 设置 RootBeanDefinition 的源对象为传入的 source 参数,这个参数表示注册的来源。

  7. RootBeanDefinition 设置属性值,将其顺序(order)设置为 Ordered.HIGHEST_PRECEDENCE,以确保它在其他Bean之前被创建。

  8. RootBeanDefinition 的角色(role)设置为 BeanDefinition.ROLE_INFRASTRUCTURE,表示它是一个基础架构角色的Bean。

  9. RootBeanDefinition 注册到 BeanDefinitionRegistry 中,使用 AUTO_PROXY_CREATOR_BEAN_NAME 作为Bean的名称。

  10. 最后,返回注册的 RootBeanDefinition 对象。

总之,这段代码描述了在BeanDefinitionRegistry中注册自动代理创建器的逻辑,并根据优先级进行必要的升级。它确保只注册具有最高优先级的自动代理创建器,并将其设置为基础架构角色的Bean。

然而在实际的使用过程中,都可能会被AnnotationAwareAspectJAutoProxyCreator替换,在同时开始了AOP和事务的情况下。具体可以看博主的另外一篇文章:SpringAOP源码解析之基础设施注册

ProxyTransactionManagementConfiguration

这个类 ProxyTransactionManagementConfiguration 是一个用于配置事务管理的Spring配置类。它继承自 AbstractTransactionManagementConfiguration,并使用了 @Configuration 注解进行标记,表示这是一个配置类。

该类中定义了以下几个方法:

  1. transactionAdvisor(): 这个方法用于创建 BeanFactoryTransactionAttributeSourceAdvisor 对象,作为事务的Advisor(通知器)。Advisor定义了在哪些切点上应用事务逻辑。该方法接收两个参数:transactionAttributeSource(事务属性源)和 transactionInterceptor(事务拦截器)。它将这两个对象设置到创建的 BeanFactoryTransactionAttributeSourceAdvisor 中,并根据需要设置Advisor的顺序。

  2. transactionAttributeSource(): 这个方法用于创建 AnnotationTransactionAttributeSource 对象,作为管理事务属性的事务属性源。AnnotationTransactionAttributeSource 是一个基于注解的事务属性源,用于从标注了事务注解的方法获取事务属性信息。

  3. 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(面向切面编程)功能。

  1. InfrastructureAdvisorAutoProxyCreator是Spring框架的一个基础设施类,用于自动创建代理对象来实现AOP。它是一个后置处理器,用于在Spring容器初始化过程中检测并自动创建适当的代理对象。它主要被用于支持基于XML配置的AOP功能。

  2. 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还是有很大的关联。我们后续将针对事物的拦截、以及事物失效规则进行源码分析。

你可能感兴趣的:(Spring专题,spring,java,后端,spring,boot,spring,cloud)