目录
1. TransactionAutoConfiguration
2. @EnableTransactionManagement
3. TransactionManagementConfigurationSelector
3.1 AutoProxyRegistrar
3.2 ProxyTransactionManagementConfiguration
3.2.1 ProxyTransactionManagementConfiguration
3.2.2 AbstractTransactionManagementConfiguration
spring boot提供的一个很好的特性就是自动配置,能够省去很多手动配置带来的烦恼,大大提升项目的开发效率;这里spring对声明式事务的支持也从自动配置说起,spring对声明式事务的原生xml支持请移步:Spring源码:声明式事务@Transactional源码分析--spring xml实现
/**
* {@link org.springframework.boot.autoconfigure.EnableAutoConfiguration
* Auto-configuration} for Spring transaction.
*
* @author Stephane Nicoll
* @since 1.3.0
*/
@Configuration
@ConditionalOnClass(PlatformTransactionManager.class)
@AutoConfigureAfter({ JtaAutoConfiguration.class, HibernateJpaAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
Neo4jDataAutoConfiguration.class })
@EnableConfigurationProperties(TransactionProperties.class)
public class TransactionAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public TransactionManagerCustomizers platformTransactionManagerCustomizers(
ObjectProvider>> customizers) {
return new TransactionManagerCustomizers(customizers.getIfAvailable());
}
@Configuration
@ConditionalOnSingleCandidate(PlatformTransactionManager.class)
public static class TransactionTemplateConfiguration {
private final PlatformTransactionManager transactionManager;
public TransactionTemplateConfiguration(
PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
@Bean
@ConditionalOnMissingBean
public TransactionTemplate transactionTemplate() {
return new TransactionTemplate(this.transactionManager);
}
}
@Configuration
@ConditionalOnBean(PlatformTransactionManager.class)
@ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)
public static class EnableTransactionManagementConfiguration {
@Configuration
@EnableTransactionManagement(proxyTargetClass = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = false)
public static class JdkDynamicAutoProxyConfiguration {
}
@Configuration
@EnableTransactionManagement(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true)
public static class CglibAutoProxyConfiguration {
}
}
}
由于在使用spring事务管理时,spring.aop.proxy-target-class默认为true,所以CglibAutoProxyConfiguration会生效,下面分析一下@EnableTransactionManagement的处理逻辑
EnableTransactionManagement主要定义了声明式事务代理目标类的方式、增强模式以及优先级,同时通过@Import注解导入了TransactionManagementConfigurationSelector implement ImportSelector,见如下源码,下面对TransactionManagementConfigurationSelector进行分析;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
/**
* Indicate whether subclass-based (CGLIB) proxies are to be created ({@code true}) as
* opposed to standard Java interface-based proxies ({@code false}). The default is
* {@code false}. Applicable only if {@link #mode()} is set to
* {@link AdviceMode#PROXY}.
* Note that setting this attribute to {@code true} will affect all
* Spring-managed beans requiring proxying, not just those marked with
* {@code @Transactional}. For example, other beans marked with Spring's
* {@code @Async} annotation will be upgraded to subclass proxying at the same
* time. This approach has no negative impact in practice unless one is explicitly
* expecting one type of proxy vs another, e.g. in tests.
*/
boolean proxyTargetClass() default false;
/**
* Indicate how transactional advice should be applied.
*
The default is {@link AdviceMode#PROXY}.
* Please note that proxy mode allows for interception of calls through the proxy
* only. Local calls within the same class cannot get intercepted that way; an
* {@link Transactional} annotation on such a method within a local call will be
* ignored since Spring's interceptor does not even kick in for such a runtime
* scenario. For a more advanced mode of interception, consider switching this to
* {@link AdviceMode#ASPECTJ}.
*/
AdviceMode mode() default AdviceMode.PROXY;
/**
* Indicate the ordering of the execution of the transaction advisor
* when multiple advices are applied at a specific joinpoint.
*
The default is {@link Ordered#LOWEST_PRECEDENCE}.
*/
int order() default Ordered.LOWEST_PRECEDENCE;
}
其继承结构如下图:
可以看出TransactionManagementConfigurationSelector本质上是一个ImportSelector,具体导入了哪些类,通过如下代码可以看出,在采用AdviceMode.PROXY时,导入了AutoProxyRegistrar和ProxyTransactionManagementConfiguration,下面分别对这两个类进行分析;
/**
* Selects which implementation of {@link AbstractTransactionManagementConfiguration}
* should be used based on the value of {@link EnableTransactionManagement#mode} on the
* importing {@code @Configuration} class.
*
* @author Chris Beams
* @since 3.1
* @see EnableTransactionManagement
* @see ProxyTransactionManagementConfiguration
* @see TransactionManagementConfigUtils#TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME
*/
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector {
/**
* {@inheritDoc}
* @return {@link ProxyTransactionManagementConfiguration} or
* {@code AspectJTransactionManagementConfiguration} for {@code PROXY} and
* {@code ASPECTJ} values of {@link EnableTransactionManagement#mode()}, respectively
*/
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
default:
return null;
}
}
}
AutoProxyRegistrar的具体实现如下,通过AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry)的方式注册了beandefinition:InfrastructureAdvisorAutoProxyCreator,和spring xml声明式事务导入了同样的自动代理创建类,完成代理的创建过程;
/**
* Registers an auto proxy creator against the current {@link BeanDefinitionRegistry}
* as appropriate based on an {@code @Enable*} annotation having {@code mode} and
* {@code proxyTargetClass} attributes set to the correct values.
*
* @author Chris Beams
* @since 3.1
* @see EnableAspectJAutoProxy
*/
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
private final Log logger = LogFactory.getLog(getClass());
/**
* Register, escalate, and configure the standard auto proxy creator (APC) against the
* given registry. Works by finding the nearest annotation declared on the importing
* {@code @Configuration} class that has both {@code mode} and {@code proxyTargetClass}
* attributes. If {@code mode} is set to {@code PROXY}, the APC is registered; if
* {@code proxyTargetClass} is set to {@code true}, then the APC is forced to use
* subclass (CGLIB) proxying.
* Several {@code @Enable*} annotations expose both {@code mode} and
* {@code proxyTargetClass} attributes. It is important to note that most of these
* capabilities end up sharing a {@linkplain AopConfigUtils#AUTO_PROXY_CREATOR_BEAN_NAME
* single APC}. For this reason, this implementation doesn't "care" exactly which
* annotation it finds -- as long as it exposes the right {@code mode} and
* {@code proxyTargetClass} attributes, the APC can be registered and configured all
* the same.
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean candidateFound = false;
Set annoTypes = importingClassMetadata.getAnnotationTypes();
for (String annoType : annoTypes) {
AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);
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) {
String name = getClass().getSimpleName();
logger.warn(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和AbstractTransactionManagementConfiguration进行说明;
源码如下,可见该类是一个Configuration类,完成了如下3个bean的定义:
这和spring xml声明式事务的定义完全一致;
/**
* {@code @Configuration} class that registers the Spring infrastructure beans
* necessary to enable proxy-based annotation-driven transaction management.
*
* @author Chris Beams
* @since 3.1
* @see EnableTransactionManagement
* @see TransactionManagementConfigurationSelector
*/
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource());
advisor.setAdvice(transactionInterceptor());
advisor.setOrder(this.enableTx.getNumber("order"));
return advisor;
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor() {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource());
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
AbstractTransactionManagementConfiguration主要完成了@EnableTransactionManagement注解属性的解析,同时通过注入TransactionManagementConfigurer类型的bean,完成事务管理器PlatformTransactionManager的设置,如下:
/**
* Abstract base {@code @Configuration} class providing common structure for enabling
* Spring's annotation-driven transaction management capability.
*
* @author Chris Beams
* @author Stephane Nicoll
* @since 3.1
* @see EnableTransactionManagement
*/
@Configuration
public abstract class AbstractTransactionManagementConfiguration implements ImportAware {
protected AnnotationAttributes enableTx;
/**
* Default transaction manager, as configured through a {@link TransactionManagementConfigurer}.
*/
protected PlatformTransactionManager txManager;
@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
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());
}
}
@Autowired(required = false)
void setConfigurers(Collection 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(name = TransactionManagementConfigUtils.TRANSACTIONAL_EVENT_LISTENER_FACTORY_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionalEventListenerFactory transactionalEventListenerFactory() {
return new TransactionalEventListenerFactory();
}
}
综上,spring声明式事务xml配置形式和spring boot自动配置形式完全一致,均完成了对spring声明式事务的支持;