本文基于Spring 5.2.7
Spring声明式事务是我们使用颇多的一种功能。从整体上来讲,他的实现原理是生成一个代理类,将所有使用声明式事务的方法重写,重写的原则就是添加上开启事务,调用目标方法,提交事务的逻辑,就这样完成了声明式事务。事务的封装完全由Spring完成,因为JDBC层面的事务使用时步骤统一且繁琐,适合用AOP封装,Spring正是基于这个原因,专门提供了spring-tx来接管数据库事务功能,方便用户使用。
一、是否需要声明@EnableTransactionManagement?
使用Spring声明式注解的方式有2种,一种是普通Spring应用,一种是拥有自动配置能力的SpringBoot,其中在没有自动配置能力的普通Spring应用中,是需要主动声明起用的,方式如下:
1、在启动类上声明@EnableTransactionManagement注解
2、在需要使用事务的方法或类型上声明@Transactional(rollbackFor = Exception.class)
在SpringBoot高版本中,事务自动配置做了升级,就不需要声明@EnableTransactionManagement注解了,直接使用@Transactional就可以了,因为自动配置帮你声明了这个注解,下面的自动配置会说明。
二、@EnableTransactionManagement注解起作用原理
@EnableTransactionManagement注解本身没有对应的操作,他只是一个引子,Spring启动时,会去扫描配置类上的注解,并且是递归搜索的,也就是说注解上的注解也会被扫描出来。这里Spring在处理配置类的时候会处理@Import注解,刚好@EnableTransactionManagement就引入了@Import注解,关键的信息还是这个@Import注解
org.springframework.transaction.annotation.EnableTransactionManagement
@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;
}
org.springframework.transaction.annotation.TransactionManagementConfigurationSelector
这个类的作用是导入其他的类,当然这里导入的类非常简单,只重写了父类的方法,一看到只有一个重写的方法,就知道是父类会调用这个方法,这里有一个参数AdviceMode,值来源于@EnableTransactionManagement(mode = AdviceMode.PROXY),他指定的是AOP增强的模式,分为代理模式和AspectJ模式,默认是代理模式。
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) {
switch (adviceMode) {
case PROXY:
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);
}
}
所以这里我们研究增强方式为代理模式下的情况,此时注入了2个bean,2个bean所在的包是不一样的,第一个是spring-context包,第二个是spring-tx包。
org.springframework.context.annotation.AutoProxyRegistrar
org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration
AutoProxyRegistrar会通过指定的BeanDefinitionRegistry注册一个auto proxy creator到容器中,同时基于@Enable*这种注解的mode、proxyTargetClass参数来设置。
这个类就一个方法,参数有2个,第一个是使用类上所有注解的元信息,第二个参数是BeanDefinitionRegistry,其实就是Ioc容器。上面使用AutoProxyRegistrar的方式和我们正常使用不一样,这个类会会注册代理后置处理,是产生代理的起点。正常情况下我们使用如下:
@Import(AutoProxyRegistrar.class)
@Enable* (mode= proxyTargetClass= )
public class A{
}
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.
* <p>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<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));
}
}
}
这里代码中执行了
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
org.springframework.aop.config.AopConfigUtils
AopConfigUtils是一个专门生成注册APC(auto-proxy creator)的工具类,当有多个实现类可用时,只应该注册一个APC。这个类提供了一个升级了的协议,它允许调用者注册一个指定的APC,作为post-processor。
public abstract class AopConfigUtils {
/**
* The bean name of the internally managed auto-proxy creator.
*/
public static final String AUTO_PROXY_CREATOR_BEAN_NAME =
"org.springframework.aop.config.internalAutoProxyCreator";
/**
* Stores the auto proxy creator classes in escalation order.
*/
private static final List<Class<?>> APC_PRIORITY_LIST = new ArrayList<>(3);
static {
// Set up the escalation list...
APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
}
@Nullable
public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAutoProxyCreatorIfNecessary(registry, null);
}
@Nullable
public static BeanDefinition registerAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}
@Nullable
public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAspectJAutoProxyCreatorIfNecessary(registry, null);
}
@Nullable
public static BeanDefinition registerAspectJAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(AspectJAwareAdvisorAutoProxyCreator.class, registry, source);
}
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
return registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry, null);
}
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
BeanDefinitionRegistry registry, @Nullable Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
public static void forceAutoProxyCreatorToUseClassProxying(BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);
}
}
public static void forceAutoProxyCreatorToExposeProxy(BeanDefinitionRegistry registry) {
if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition definition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
definition.getPropertyValues().add("exposeProxy", Boolean.TRUE);
}
}
@Nullable
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())) {
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;
}
private static int findPriorityForClass(Class<?> clazz) {
return APC_PRIORITY_LIST.indexOf(clazz);
}
private static int findPriorityForClass(@Nullable String className) {
for (int i = 0; i < APC_PRIORITY_LIST.size(); i++) {
Class<?> clazz = APC_PRIORITY_LIST.get(i);
if (clazz.getName().equals(className)) {
return i;
}
}
throw new IllegalArgumentException(
"Class name [" + className + "] is not a known auto-proxy creator class");
}
}
org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration
这个类被@Role修饰为基础设施角色,他继承了AbstractTransactionManagementConfiguration,我们稍后再看父类,这里向容器注册了3个类,也都是基础设施角色。
org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor
org.springframework.transaction.interceptor.TransactionAttributeSource
org.springframework.transaction.interceptor.TransactionInterceptor
BeanFactoryTransactionAttributeSourceAdvisor是一个Advisor,用来持有Advice,TransactionAttributeSource不知道干啥的,TransactionInterceptor是一个Advice,用来描述增强的具体操作。
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource);
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();
}
@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;
}
}
三、自动配置启用事务的原理
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration
这个类被归在了自动配置的jdbc包下,依赖
org.springframework.jdbc.core.JdbcTemplate spring-jdbc
org.springframework.transaction.PlatformTransactionManager spring-tx
所以基于DataSource的事务管理必须要引入spring-jdbc和spring-tx这2个包
这里要求只有一个数据源才载入事务管理器
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ JdbcTemplate.class, PlatformTransactionManager.class })
@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceTransactionManagerAutoConfiguration {
@Configuration(proxyBeanMethods = false)
@ConditionalOnSingleCandidate(DataSource.class)
static class DataSourceTransactionManagerConfiguration {
@Bean
@ConditionalOnMissingBean(PlatformTransactionManager.class)
DataSourceTransactionManager transactionManager(DataSource dataSource,
ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(dataSource);
transactionManagerCustomizers.ifAvailable((customizers) -> customizers.customize(transactionManager));
return transactionManager;
}
}
}
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration
这里出现了@EnableTransactionManagement这个注解,也说明了为什么在SpringBoot高版本中为什么可以不用声明@EnableTransactionManagement这个注解就能启用事务。
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(PlatformTransactionManager.class) // 须引入spring-tx包
@AutoConfigureAfter({ JtaAutoConfiguration.class, HibernateJpaAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class, Neo4jDataAutoConfiguration.class })
@EnableConfigurationProperties(TransactionProperties.class) // 将配置映射到指定bean中
public class TransactionAutoConfiguration {
@Bean
@ConditionalOnMissingBean // 没有才注入
public TransactionManagerCustomizers platformTransactionManagerCustomizers(
ObjectProvider<PlatformTransactionManagerCustomizer<?>> customizers) {
return new TransactionManagerCustomizers(customizers.orderedStream().collect(Collectors.toList()));
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnSingleCandidate(ReactiveTransactionManager.class) // 容器中ReactiveTransactionManager只有一个才有效
public TransactionalOperator transactionalOperator(ReactiveTransactionManager transactionManager) {
return TransactionalOperator.create(transactionManager);
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnSingleCandidate(PlatformTransactionManager.class)
public static class TransactionTemplateConfiguration {
@Bean
@ConditionalOnMissingBean(TransactionOperations.class)
public TransactionTemplate transactionTemplate(PlatformTransactionManager transactionManager) {
return new TransactionTemplate(transactionManager);
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(TransactionManager.class)
@ConditionalOnMissingBean(AbstractTransactionManagementConfiguration.class)
public static class EnableTransactionManagementConfiguration {
// 如果spring.aop.proxy-target-class=false
@Configuration(proxyBeanMethods = false)
@EnableTransactionManagement(proxyTargetClass = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false",
matchIfMissing = false)
public static class JdkDynamicAutoProxyConfiguration {
}
// 如果spring.aop.proxy-target-class=true
@Configuration(proxyBeanMethods = false)
@EnableTransactionManagement(proxyTargetClass = true)
@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
matchIfMissing = true)
public static class CglibAutoProxyConfiguration {
}
}
}
一、@Transactional的BeanPostProcessor
要生成代 理类,必须要有处理者,那么是谁在处理@Transactional注解代理类的生成?
AbstractAutoProxyCreator