当前位置: 首页 > ai >正文

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

系列文章目录

前言

上一篇介绍了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);//设置adviceadvisor.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@Nullableprotected TransactionAttributeSource getTransactionAttributeSource() {return transactionAttributeSource;}};
@Overridepublic 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() {@Overridepublic void suspend() {System.out.println("A被挂起了");}@Overridepublic 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的BeanDefinitionRootBeanDefinition 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属性
http://www.xdnf.cn/news/6348.html

相关文章:

  • PostgreSQL malformed array literal异常
  • PostgreSQL pgrowlocks 扩展详解
  • 1267, “Illegal mix of collations (latin1_swedish_ci,IMPLICIT
  • 【重磅】配电网智能软开关和储能联合规划
  • 专项智能练习(定义判断)_DA_02
  • redis解决常见的秒杀问题
  • IP地址查询可以了解到哪些宿主信息
  • 地球阿米特黑客组织使用新型工具攻击军用无人机供应链
  • 介绍一下什么是 AI、 AGI、 ASI
  • 解决 Ubuntu 22.04 安装后启动卡死问题
  • 在文件检索方面doris和elasticsearch的区别
  • Kotlin 和 Java 混合开发时需要注意哪些问题
  • 信息系统运行管理员:临阵磨枪版
  • 01-数据结构概述和时间空间复杂度
  • 多模态大语言模型arxiv论文略读(七十六)
  • 插件双更新:LeetCode 刷题支持正式上线,JetBrains IDE 插件持续升级!
  • 前端图形渲染 html+css、canvas、svg和webgl绘制详解,各个应用场景及其区别
  • 加一个JVM参数,让系统可用率从95%提高到99.995%
  • java实现根据Velocity批量生成pdf并合成zip压缩包
  • 023-C语言预处理详解
  • 使用GoLang版MySQLDiff对比表结构
  • 大模型之Dify之踩坑集锦
  • undefined reference to `typeinfo for DeviceAllocator‘
  • 深入理解浏览器渲染引擎:底层机制与性能优化实战
  • BFD与VRRP联动
  • 高云FPGA-新增输出管脚约束
  • STM32 SD卡拔插后FatFs挂载失败可能原因
  • ACI Fabric 中的各种地址
  • L - Strange Mirroring (思维)
  • Datawhale 5月llm-universe 第2次笔记