【spring】spring源码系列之十:spring事务管理(下)

发布于:2025-05-16 ⋅ 阅读:(19) ⋅ 点赞:(0)

系列文章目录

前言

上一篇介绍了spring事务管理的几个组件,这一篇我们从@EnableTransactionManagement注解开始看spring的事务管理

一、springframework的事务管理

从@EnableTransactionManagement注解开始,spring就开启了事务管理,所以我们从这里开始看源码

1.引入组件

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
。。。
}

通过引入TransactionManagementConfigurationSelector最终引入了两个组件:
1)注册了一个BPP:InfrastructureAdvisorAutoProxyCreator
这个BPP
2)注册了一个Advisor:BeanFactoryTransactionAttributeSourceAdvisor。而BeanFactoryTransactionAttributeSourceAdvisor是一个PointcutAdvisor的实现类,我们在AOP那一篇讲过PointcutAdvisor的2个关键方法,就是获取pointcut和advice。BeanFactoryTransactionAttributeSourceAdvisor的实现如下:

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();
		//设置pointcut的属性,pointcut的matches方法就是由transactionAttributeSource完成的
		advisor.setTransactionAttributeSource(transactionAttributeSource);
		//设置advice
		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;
	}

}
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
		@Override
		@Nullable
		protected TransactionAttributeSource getTransactionAttributeSource() {
			return transactionAttributeSource;
		}
	};
@Override
	public boolean matches(Method method, Class<?> targetClass) {
		TransactionAttributeSource tas = getTransactionAttributeSource();
		return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
	}

2.解析@Transactional注解

我们在AOP那一篇讲过初始化后方法创建代理对象,同样,在执行InfrastructureAdvisorAutoProxyCreator这个BPP的初始化后方法时,会创建事务的代理对象
1)获取所有候选的Advisor
2)从候选Advisor中获取可以用于该bean的advisors(执行pointcut的matches方法)
3)对符合的bean创建代理对象
所以,BeanFactoryTransactionAttributeSourceAdvisor作为候选的advisor,执行其pointcut的matches方法,最终执行的是TransactionAttributeSource 的getTransactionAttribute方法,筛选的逻辑就是判断方法或类或接口方法或接口上是否有@Transactional注解
最终对方法或类或接口方法或接口上有@Transactional注解的创建了代理对象

public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
		if (method.getDeclaringClass() == Object.class) {
			return null;
		}

		// First, see if we have a cached value.
		Object cacheKey = getCacheKey(method, targetClass);
		TransactionAttribute cached = this.attributeCache.get(cacheKey);
		if (cached != null) {
			// Value will either be canonical value indicating there is no transaction attribute,
			// or an actual transaction attribute.
			if (cached == NULL_TRANSACTION_ATTRIBUTE) {
				return null;
			}
			else {
				return cached;
			}
		}
		else {
			// We need to work it out.
			TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
			// Put it in the cache.
			if (txAttr == null) {
				this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
			}
			else {
				String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
				if (txAttr instanceof DefaultTransactionAttribute) {
					((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
				}
				if (logger.isTraceEnabled()) {
					logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
				}
				this.attributeCache.put(cacheKey, txAttr);
			}
			return txAttr;
		}
	}

3.调用入口

同AOP
1)遍历候选的advisor,将匹配要调用方法的advisor的advice取出来,生成拦截器链
2)按照拦截器链顺序递归调用
此时对于BeanFactoryTransactionAttributeSourceAdvisor来说,只有方法上有@Transactional注解才会取出BeanFactoryTransactionAttributeSourceAdvisor的advice生成拦截器链进行调用

调用入口就是TransactionInterceptor的invoke方法

public Object invoke(MethodInvocation invocation) throws Throwable {
		Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

		// Adapt to TransactionAspectSupport's invokeWithinTransaction...
		//spring事务调用入口
		return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
	}

4.事务执行

//获取@Transactional注解上配置的属性
TransactionAttributeSource tas = getTransactionAttributeSource();
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
...
//获取事务管理器
PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
//获取切入点
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
			//1.创建事务
			// Standard transaction demarcation with getTransaction and commit/rollback calls.
			TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

			Object retVal;
			try {
				// This is an around advice: Invoke the next interceptor in the chain.
				// This will normally result in a target object being invoked.
				//2.执行事务中的业务
				retVal = invocation.proceedWithInvocation();
			}
			catch (Throwable ex) {
				// target invocation exception
				//3.回滚事务
				completeTransactionAfterThrowing(txInfo, ex);
				throw ex;
			}
			finally {
				//4.清理事务
				cleanupTransactionInfo(txInfo);
			}

			if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
				// Set rollback-only in case of Vavr failure matching our rollback rules...
				TransactionStatus status = txInfo.getTransactionStatus();
				if (status != null && txAttr != null) {
					retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
				}
			}
			//提交事务
			commitTransactionAfterReturning(txInfo);
			return retVal;
		}

1)创建事务
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
这里创建了TransactionInfo ,其实就是对TransactionManager和TansactionStatus的封装(前面讲过TransactionManager中创建事务时返回的是TansactionStatus)。TransactionInfo多封装了transactionAttribute(@Transactional中的属性,比如隔离级别、事务的传播方式、rollbackon属性)、joinpointIdentification(事务的名称)、oldTransactionInfo(上层事务信息)。我们在使用TranactionTemplate时需要手动set隔离级别、事务的传播方式、事务的名称。那么这里就都封装到TransactionInfo中了。

private final PlatformTransactionManager transactionManager;
private final TransactionAttribute transactionAttribute;
private final String joinpointIdentification;
private TransactionStatus transactionStatus;
private TransactionInfo oldTransactionInfo;

而oldTransactionInfo是上层事务信息的引用,形成了一个事务信息的链表,用于后续恢复上层事务。在创建TransactionInfo 时,先获取上层TransactionInfo,再将本层的TransactionInfo放到ThreadLocal中

private void bindToThread() {
			this.oldTransactionInfo = transactionInfoHolder.get();
			transactionInfoHolder.set(this);
		}

2)执行事务中的信息
这里就是递归执行

3)回滚事务
completeTransactionAfterThrowing(txInfo, ex);
上面说了TransactionInfo是对TansactionStatus的封装,所以这里回滚事务的逻辑本质是调用TransactionManager回滚TansactionStatus的方法,只是多了对rollbackOn判断的功能,也就是指定回滚的异常类型。如果不是指定的回滚类型,那么就提交事务。如何回滚和提交,前面讲TransactionManager已经讲过

if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
	try {
	txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
				}
	...
	}
	else {
	try {
	txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
				}
	...
	}

4)清理事务
cleanupTransactionInfo(txInfo);
就是恢复上层的TransactionInfo,也就是将oldTransactionInfo重新放到ThreadLocal中

private void restoreThreadLocalStatus() {
			transactionInfoHolder.set(this.oldTransactionInfo);
		}

5)提交事务
commitTransactionAfterReturning(txInfo);
就是调用TransactionManager对TransactionStatus进行提交,前面已经讲过了

txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());

5.小结:

1)springframework的事务管理通过引入2个组件将@Transacional注解的方法解析成代理对象,在代理对象中开始事务的执行流程
2)执行时,通过TransactionInfo封装了TransactionManager和TansactionStatus,最终还是执行的TransactionManager中的事务方法,只是多了一些功能

二、事务的生命周期方法

事务的生命周期方法主要涉及事务的创建、提交、回滚和销毁等阶段。
TransactionSynchronizationManager使用示例:

@Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void testA() {
        TransactionSynchronizationManag事务的er.registerSynchronization(new TransactionSynchronization() {
            @Override
            public void suspend() {
                System.out.println("A被挂起了");
            }

            @Override
            public void resume() {
                System.out.println("A被恢复了");
            }
        });
        jdbcTemplate.update("update customer set cust_name='snow2' where id = 1");
    }

就不展开介绍了

三、TransactionInfo封装的功能

1.事务的隔离级别

在Spring中,可以通过 @Transactional 注解或编程式事务管理来设置事务的隔离级别。

@Transactional(isolation = Isolation.READ_COMMITTED)
public void someMethod() {
    // 业务逻辑
}

2.事务的传播方式

@Service
public class OrderService {

    @Transactional(propagation = Propagation.REQUIRED)
    public void placeOrder(Order order) {
        // 如果当前有事务,则加入;否则新建事务
        // 业务逻辑...
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void updateInventory(Product product) {
        // 始终新建事务,挂起当前事务(如果有)
        // 业务逻辑...
    }
}

3.指定回滚的异常类型

rollbackon属性:只有出现这些异常类型时才会回滚
noRollbackFor属性:出现这类异常时不会滚

@Transactional(rollbackon = {SQLException.class, InsufficientBalanceException.class})
public void transferMoney(Account from, Account to, double amount) throws InsufficientBalanceException {
    // 当抛出 SQLException 或 InsufficientBalanceException 时,事务回滚
}
@Transactional(noRollbackFor = {IllegalArgumentException.class})
public void updatePrice(Product product, double newPrice) {
    // 即使抛出 IllegalArgumentException,事务也不会回滚
}

四、事务代理与AOP代理是否冲突

  1. @EnableTransactionManagement注解注册了一个BPP:InfrastructureAdvisorAutoProxyCreator,我们在介绍AOP时,开启AOP,使用@EnableAspectJAutoProxy注解注册了AnnotationAwareAspectJAutoProxyCreator,这两个BPP都在初始化后方法中发挥作用,会不会产生冲突呢(比如事务代理了一遍,AOP又代理了一遍,是不是事务会开启2次)?
    我们先看看@EnableTransactionManagement注解是怎么注册InfrastructureAdvisorAutoProxyCreator的
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
AdviceMode mode() default AdviceMode.PROXY;
}

//TransactionManagementConfigurationSelector的selectImports方法
protected String[] selectImports(AdviceMode adviceMode) {
		switch (adviceMode) {
			//上面看到EnableTransactionManagement的mode属性默认是PROXY,所以走这里
			case PROXY:
				return new String[] {AutoProxyRegistrar.class.getName(),
						ProxyTransactionManagementConfiguration.class.getName()};
			case ASPECTJ:
				return new String[] {determineTransactionAspectClass()};
			default:
				return null;
		}
	}

//AutoProxyRegistrar
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;
					}
				}
			}
		}
}

public static BeanDefinition registerAutoProxyCreatorIfNecessary(
			BeanDefinitionRegistry registry, @Nullable Object source) {
		return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
	}

1)先通过导入ImportSelector的方式注册了AutoProxyRegistrar
2)AutoProxyRegistrar是一个ImportBeanDefinitionRegistrar,在registerBeanDefinitions方法中
调用registerAutoProxyCreatorIfNecessary方法对InfrastructureAdvisorAutoProxyCreator进行注册,
继续看registerOrEscalateApcAsRequired方法

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;
		}
		//如果不存在,则创建beanName为AUTO_PROXY_CREATOR_BEAN_NAME的BeanDefinition
		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;
	}

3)在registerOrEscalateApcAsRequired方法中会判断是否有beanName为AUTO_PROXY_CREATOR_BEAN_NAME的BeanDefinition,如果有,则比较优先级,留下优先级高的,如果不存在则新建

@EnableAspectJAutoProxy注解注册AnnotationAwareAspectJAutoProxyCreator也是类似的逻辑,就不贴代码了

所以,容器中只会留下优先级最高的那个,那么就不会产生冲突了

总结

  1. spring通过@EnableTransactionManagement开启事务,引入了2个组件InfrastructureAdvisorAutoProxyCreator和BeanFactoryTransactionAttributeSourceAdvisor。
    1)InfrastructureAdvisorAutoProxyCreator用于初始化后进行AOP
    2)BeanFactoryTransactionAttributeSourceAdvisor中有拦截器TransactionInterceptor用于开启、提交、回滚事务。有PointCut用于判断对哪些类生成代理(判断方法或类或接口方法或接口上是否有@Transactional注解,有就创建代理)
  2. 方法调用:同AOP,将匹配方法的advisor中的拦截器生成拦截器链,最终执行TransactionInterceptor的invoke方法。执行时,通过TransactionInfo封装了TransactionManager和TansactionStatus,最终还是执行的TransactionManager中的事务方法,只是多了一些功能,比如隔离级别、事务的传播方式、rollbackon属性

网站公告

今日签到

点亮在社区的每一天
去签到