Foreword
@EnableTransactionManagement
is an annotation provided by the Spring framework to enable annotation-based transaction management. By using this annotation, you can enable Spring’s automatic management of transactions, allowing you to use the @Transactional
annotation on methods to declare transactions.
@EnableTransactionManagement
mainly has the following two attributes:
-
mode (default is
AdviceMode.PROXY
): Specifies the mode of the transaction agent. Possible values to choose from areAdviceMode.PROXY
andAdviceMode.ASPECTJ
. The default isAdviceMode.PROXY
, which means using proxy-based transaction management. If you selectAdviceMode.ASPECTJ
, it means using AspectJ-based method to implement transaction management. -
proxyTargetClass (default
false
): Used to determine whether the proxy should use the target class’s class proxy, rather than the interface implemented by the target class. If set totrue
, the proxy will use the class proxy of the target class (CGLIB proxy). If set tofalse
, the proxy will use the interface proxy implemented by the target class (JDK dynamic proxy). ).
When you use the @EnableTransactionManagement
annotation on a configuration class, the Spring framework will automatically scan for methods annotated with @Transactional
and weave transaction management logic around these methods. . If an exception occurs during the execution of a method annotated with @Transactional
, Spring will automatically roll back the transaction. The purpose of this annotation is to simplify the configuration and use of transaction management and improve development efficiency.
Example:
@Configuration @EnableTransactionManagement(mode = AdviceMode.PROXY, proxyTargetClass = false) public class AppConfig {<!-- --> // ... }
In this example, @EnableTransactionManagement
enables proxy-based transaction management, using the default proxy mode and interface proxy. You can adjust the values of these two properties as needed.
Source code analysis
First check the @EnableTransactionManagement annotation and use the @import annotation to import a class: 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
By default mode = AdviceMode.PROXY, so the selectImports(AnnotationMetadata importingClassMetadata) method will be called when the configuration class is parsed.
That is, the selectImports(AnnotationMetadata importingClassMetadata) method of the AdviceModeImportSelector class will be called, and then the selectImports(AdviceMode adviceMode) method of TransactionManagementConfigurationSelector will be called, which involves the use of 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 annotation defaults to Proxy switch (adviceMode) {<!-- --> case PROXY: //Then we need to load the classes in this array. At this point, the @EnableTransactionManagement annotation is completed. 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); } }
The String array returned by selectImports(AdviceMode adviceMode) will convert the classes in this array into BeanDefinitions and register them in the container.
The
ConfigurationClassParser
class is the configuration class responsible for parsing the @Configuration annotation.The
ConfigurationClassBeanDefinitionReader
class is an auxiliary class ofConfigurationClassParser
, which is used to convert the parsed configuration class information into a BeanDefinition object and register it in the Spring container.The main responsibility of the
ConfigurationClassParser
class is to scan and parse configuration classes with @Configuration annotations. It will parse various annotations, methods and fields in the class to determine the beans to be created and configured. It processes @Configuration annotations, @Bean annotations, @ComponentScan annotations, @Import annotations, etc., and generates corresponding BeanDefinition objects based on these annotations.Once
ConfigurationClassParser
completes parsing the configuration class, it will pass the parsed BeanDefinition objects toConfigurationClassBeanDefinitionReader
, which is responsible for registering these BeanDefinition objects into the Spring container.Therefore,
ConfigurationClassParser
andConfigurationClassBeanDefinitionReader
work together. One is responsible for parsing and processing the @Configuration annotated configuration class, and the other is responsible for converting the parsing results into BeanDefinition and registering it in the container. .
AutoProxyRegistrar
The AutoProxyRegistrar class implements the ImportBeanDefinitionRegistrar interface, and its function is to register the automatic proxy creator (AutoProxyCreator) in the Spring container.
Specifically, the registerBeanDefinitions() method is a method in the ImportBeanDefinitionRegistrar interface, which will be called during the initialization process of the configuration class (or usage). This method receives two parameters:
importingClassMetadata
: used to obtain metadata of imported classes, such as annotation information, class name, etc.registry
: BeanDefinitionRegistry object used to register BeanDefinition.
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 & amp; & amp; proxyTargetClass != null & amp; & amp; AdviceMode.class == mode.getClass() & amp; & amp; Boolean.class == proxyTargetClass.getClass()) {<!-- --> candidateFound = true; if (mode == AdviceMode.PROXY) {<!-- --> AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry); if ((Boolean) proxyTargetClass) {<!-- --> AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); return; } } } } if (!candidateFound & amp; & amp; 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)); } } }
In the registerBeanDefinitions()
method, first obtain all annotation types on the configuration class through importingClassMetadata
. Then iterate through these annotation types and try to obtain the mode
and proxyTargetClass
attribute values on the annotation.
If an annotation with mode
and proxyTargetClass
attributes is found and their types are AdviceMode
and boolean
respectively, then Indicates that a candidate automatic proxy creator was found. According to the value of the mode
attribute, if it is AdviceMode.PROXY
, the AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry)
method is called to register the automatic proxy creator.
If the proxyTargetClass
attribute is true
, call the AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry)
method to force the automatic proxy creator to use the class proxy mode. Then, the method returns to complete the registration process.
If annotations with mode
and proxyTargetClass
attributes are not found on the configuration class, or other exceptions occur, a warning log will be printed, indicating that automatic proxying may not be performed as expected. Producer registration and configuration.
In short, the registerBeanDefinitions()
method of the AutoProxyRegistrar
class determines whether to register the automatic proxy creator by checking the annotations on the configuration class, and configures it accordingly based on the attribute values of the annotations. This can realize the automatic proxy function, which is used to proxy components marked with specific annotations.
InfrastructureAdvisorAutoProxyCreator
First, AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry); actually registers the definition information of the beans produced by InfrastructureAdvisorAutoProxyCreator into the container. But in fact there will be an overridden behavior, as shown in the following method code:
private static BeanDefinition registerOrEscalateApcAsRequired( Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {<!-- --> Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); \t\t if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {<!-- --> BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); if (!cls.getName().equals(apcDefinition.getBeanClassName())) {<!-- --> // currentPriority What is the position of the currently injected class? //APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class); 0 //APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class); 1 //APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class); 2 // That is to say, the bottom one can cover the top one. 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; }
Briefly analyze the implementation of registerOrEscalateApcAsRequired. This method is used to register the automatic proxy creator (AutoProxyCreator) in the BeanDefinitionRegistry and perform necessary upgrades based on priority.
The main logic of the method is as follows:
-
First, make sure that the
BeanDefinitionRegistry
parameter passed in is not null, otherwise an exception will be thrown. -
Checks whether a BeanDefinition named
AUTO_PROXY_CREATOR_BEAN_NAME
is already included in theBeanDefinitionRegistry
, whereAUTO_PROXY_CREATOR_BEAN_NAME
is the name of the automatic proxy creator. -
If the BeanDefinition of the automatic proxy creator already exists, it is further determined whether the class of the automatic proxy creator currently to be registered is the same as the class of the existing BeanDefinition. If they are different, it means that a higher priority automatic proxy creator has been registered and needs to be upgraded.
-
Determine whether the class of the automatic agent creator currently being registered has a higher priority by comparing the priorities of the automatic agent creator classes. The priority is determined through the
findPriorityForClass
method. If the class priority of the automatic proxy creator currently to be registered is higher, update the existing BeanDefinition class to the class currently to be registered. -
If the BeanDefinition of the automatic proxy creator does not exist, create a
RootBeanDefinition
object whose class is the class of the automatic proxy creator currently to be registered. -
Set the source object of
RootBeanDefinition
to the passed insource
parameter. This parameter indicates the source of registration. -
Set the property value for
RootBeanDefinition
and set its order toOrdered.HIGHEST_PRECEDENCE
to ensure it is created before other beans. -
Set the role of
RootBeanDefinition
toBeanDefinition.ROLE_INFRASTRUCTURE
, indicating that it is a Bean with an infrastructure role. -
Register
RootBeanDefinition
intoBeanDefinitionRegistry
, usingAUTO_PROXY_CREATOR_BEAN_NAME
as the name of the Bean. -
Finally, the registered
RootBeanDefinition
object is returned.
In summary, this code describes the logic of registering the automatic proxy creator in the BeanDefinitionRegistry and making necessary upgrades based on priority. It ensures that only the automatic proxy creator with the highest priority is registered and set as a bean for the infrastructure role.
However, in actual use, it may be replaced by AnnotationAwareAspectJAutoProxyCreator when AOP and transactions are started at the same time. For details, you can read another article by the blogger: SpringAOP source code analysis and infrastructure registration
ProxyTransactionManagementConfiguration
This class ProxyTransactionManagementConfiguration
is a Spring configuration class used to configure transaction management. It inherits from AbstractTransactionManagementConfiguration
and is marked with the @Configuration
annotation, indicating that this is a configuration class.
The following methods are defined in this class:
-
transactionAdvisor()
: This method is used to create aBeanFactoryTransactionAttributeSourceAdvisor
object as the transaction advisor (notifier). Advisor defines at which cut points the transaction logic is applied. This method receives two parameters:transactionAttributeSource
(transaction attribute source) andtransactionInterceptor
(transaction interceptor). It sets these two objects into the createdBeanFactoryTransactionAttributeSourceAdvisor
and sets the order of the advisors as needed. -
transactionAttributeSource()
: This method is used to create aAnnotationTransactionAttributeSource
object as a transaction attribute source that manages transaction attributes.AnnotationTransactionAttributeSource
is an annotation-based transaction attribute source, used to obtain transaction attribute information from methods marked with transaction annotations. -
transactionInterceptor()
: This method is used to create aTransactionInterceptor
object as a transaction interceptor.TransactionInterceptor
is an AOP interceptor used to apply transaction logic before and after method calls. It receives atransactionAttributeSource
parameter, which is used to obtain transaction attribute information. If atxManager
(transaction manager) is configured, set it to theTransactionInterceptor
created.
These methods declare themselves as beans using the @Bean
annotation and specify their roles as infrastructure roles using the @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
annotation. This means that they are components used internally by the framework to support transaction management functionality.
In the configuration, the transactionAdvisor()
method creates a transaction advisor, which combines transaction attribute sources and transaction interceptors to enhance pointcuts to achieve transaction management. The transactionAttributeSource()
method creates an annotation transaction attribute source for managing transaction attribute information. The transactionInterceptor()
method creates a transaction interceptor that applies transaction logic before and after method execution.
By using these methods to create corresponding components and registering them as beans in the Spring container, transaction management and interception can be achieved.
The methods in this class are used to configure related components of transaction management, including transaction advisor, transaction attribute source and transaction interceptor. They are key components that support Spring transaction management and are used to implement declarative transaction functions.
@Configuration(proxyBeanMethods = false) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {<!-- --> @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) // To enhance the cut point, an Advisor is naturally needed public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor( TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {<!-- --> // Instantiate the advisor object BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor(); //Introduce the second bean advisor.setTransactionAttributeSource(transactionAttributeSource); //Introduce the third bean advisor.setAdvice(transactionInterceptor); if (this.enableTx != null) {<!-- --> advisor.setOrder(this.enableTx.<Integer>getNumber("order")); } return advisor; } // This is for managing transaction attributes @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public TransactionAttributeSource transactionAttributeSource() {<!-- --> return new AnnotationTransactionAttributeSource(); } //Interceptor required by 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 and AnnotationAwareAspectJAutoProxyCreator
InfrastructureAdvisorAutoProxyCreator and AnnotationAwareAspectJAutoProxyCreator are two key classes in the Spring Framework, used to implement AOP (aspect-oriented programming) functions.
-
InfrastructureAdvisorAutoProxyCreator is an infrastructure class of the Spring framework, used to automatically create proxy objects to implement AOP. It is a post-processor that detects and automatically creates appropriate proxy objects during Spring container initialization. It is mainly used to support AOP functions based on XML configuration.
-
AnnotationAwareAspectJAutoProxyCreator is an automatic proxy creator in the Spring framework to support annotation-based AOP functionality. It inherits from InfrastructureAdvisorAutoProxyCreator, and adds parsing and processing of annotations on its basis. It scans the beans in the Spring container, detects the use of AOP-related annotations (such as @Aspect, @Before, @After, etc.), and then automatically creates the corresponding proxy object.
By using these two classes, the Spring framework can automatically create proxy objects based on configuration and annotation information to implement AOP functions. AOP allows developers to apply cross-cutting concerns (Cross-cutting Concerns) to different parts of the application, such as logging, performance monitoring, transaction management, etc., by defining aspects and advices.
In the Spring framework, an InfrastructureAdvisorAutoProxyCreator (also known as the parent class of AnnotationAwareAspectJAutoProxyCreator) is registered by default. This class is an infrastructure class of Spring for supporting AOP functionality.
When you use the @EnableAspectJAutoProxy annotation, Spring will automatically replace InfrastructureAdvisorAutoProxyCreator with the more advanced AnnotationAwareAspectJAutoProxyCreator. AnnotationAwareAspectJAutoProxyCreator inherits from InfrastructureAdvisorAutoProxyCreator, and adds parsing and processing of annotations on its basis to support annotation-based AOP functions.
By using the @EnableAspectJAutoProxy annotation, you can enable annotation-based AOP functionality and configure aspects and advice using annotations without explicitly configuring AOP in XML. That is to say, when you use the @EnableAspectJAutoProxy annotation, Spring will automatically upgrade to AnnotationAwareAspectJAutoProxyCreator, thereby enabling annotation-based AOP functionality.
Summary
This article describes what the @EnableTransactionManagement annotation does during initialization. In fact, it is still closely related to AOP. We will conduct source code analysis on the interception of things and the failure rules of things in the future.