分布式事务实战八(Spring事务框架源码初探一)

通过上节的讲解,我们现在已经知道,基于AOP是可以实现与@Transactional注解相似的效果,其实@Transactional注解就是基于AOP来实现的呢?因为我们知道,从IOC容器获取bean的时候,获取到是一个代理对象,也就是说上边获取的flowRechargeCenterService这个bean就是一个代理对象,然后在这个代理对象中实现了开启事务、回滚事务和提交事务的逻辑。我们可以debug来看下flowRechargeCenterService这个bean到底是什么,我们先排除我们自定义切面类的影响,先注释这个类。
在这里插入图片描述
我们在debug flowRechargeCenterService这个对象, 此时debug结果如下:
在这里插入图片描述
通过上图,我们可以看到,这个flowRechargeCenterService就是一个代理对象,并且还是cglib代理对象。说白了@Transactional注解就是基于AOP来实现的,也就是说,只要方法上加了@Transactional注解,那么Spring就会为这个方法所在的类创建一个代理出来,而当调用代理对象的方法时,就会执行代理中的增强逻辑来支持事务。那接下来的重点,当然就是要来看下这个增强逻辑中,到底是怎么支持事务的,那这个增强逻辑该怎么找呢?我在Spring AOP源码分析的教程分析过的,大家可以看一下我的AOP的源码分析,这样我们才能的理解spring事务的源码,我们现在到cglib执行AOP增强的方法看下:
在这里插入图片描述
在这里插入图片描述
这里其实就是不断地调用父类ReflectiveInvocation的proceed方法,然后在拦截器链interceptorsAndDynamicMethodMatchers中拦截器的invoke()方法,而这些拦截器其实就是一个一个的增强。那现在问题来了,对于@Transactional注解来说,拦截器链中会有哪些增强呢?我们同样可以使用debug来看下拦截器链interceptorsAndDynamicMethodMatchers中,到底有哪些拦截器,此时debug结果如下:
在这里插入图片描述
通过上图,可以看到,其实拦截器链interceptorsAndDynamicMethodMatchers中,只有一个拦截器,那就是TransactionInterceptor。也就是说对于@Transactional注解来说,拦截器链中其实只有TransactionInterceptor这一个拦截器,那这个TransactionInterceptor都会做些什么事情呢?我们必须要深入TransactionInterceptor拦截器的invoke()方法来一探究竟了,此时我们会看到下边这块代码:
在这里插入图片描述
在上边的代码中,关键的是调用了invokeWithinTransaction()方法,这个方法从名字上来看是在事务内调用的意思,说明这个核心逻辑就在这个invokeWithinTransaction()方法中。那接下来,我们当然是要来看下这个invokeWithinTransaction()方法了,此时代码如下:
在这里插入图片描述
上边就是invokeWithinTransaction()方法的核心代码了,其中一些不太重要的代码已经省略了,我们可以看到,在上面的代码中,首先是调用了一个createTransactionIfNecessary()方法,从这个方法的名字上来看是创建事务的意思,其实说白了就是开启事务的意思。接着调用了retVal = invocation.proceedWithInvocation()这行代码来执行目标方法,而且在这行代码中,做了try catch处理,在这个catch语句块中调用了一个completeTransactionAfterThrowing()方法,从这个方法的名字来看是发生异常后完成的事务,其实就是发生异常时回滚事务的意思,并且回滚完事务之后,通过throw ex将异常直接抛了出去。如果执行目标方法没有发生异常,那么就会调用commitTransactionAfterReturning()方法,从名字上来看这个方法是返回后提交事务的意思,其实就是目标方法正常执行结束后,如果没有发生异常,那么就直接提交事务的意思。大家有没有发现,上边这块代码的逻辑,和上节我们基于AOP模拟事务的代码非常相似?所以说这个@Transactional注解的本质就是基于AOP来实现的,而实现事务的核心逻辑,其实就是在执行目标方法之前,先开启事务,然后再来执行目标方法,因为目标方法是加了try catch处理的,所以当执行目标方法发生异常时,由catch语句块来做特殊处理,说白了就是回滚事务,如果未发生异常,那么就直接提交事务。

我们就接着来看下这个TransactionInterceptor控制事务的内部细节。我们知道如果我们想要在代码层面开启事情,我们需要通过Connection.setAutoCommit(false)来完成,如果执行成功了,我们会通过Connection.commit()来提交事务,如果我们的业务执行失败了,我们会通过Connection.rollback()来回滚事务。我们继续往下分析,首先我们从开启事务开始分析,也就是createTransactionIfNecessary()方法,如下图:
在这里插入图片描述
在这里插入图片描述
上边createTransactionIfNecessary()方法的代码,其中非常关键的一行代码就是tm.getTransaction(txAttr),看名字这行代码是获取到了一个事务。我们继续往下深入,此时会看到下边这块代码:
在这里插入图片描述在这里插入图片描述
此时我们发现,在startTransaction()方法中调用了doBegin()方法。开启事务的逻辑就在这个doBegin()方法中了,此时doBegin()方法的代码如下:
在这里插入图片描述
上边的代码中,我们看到了极为重要的一行代码,那就是con.setAutoCommit(false),而这个con就是Connection类型,就是一个jdbc连接。也就是说,开启事务的本质,就是通过Connection来完成的。现在事务已经开启成功了,那么接下来就就要执行目标方法了,也就是下边这行代码:
在这里插入图片描述
通过上图,可以看到,其实就是通过invocation.proceedWithInvocation()这行代码,来执行目标方法的,而这个invocation我们可以看到,其实是从外边传进来的。而我们知道,其实是在TransactionInterceptor拦截器中调用的invokeWithinTransaction()方法,那现在我们再回头来看下TransactionInterceptor拦截器的代码,主要就是来看下在调用invokeWithinTransaction()方法时,入参invocation传递的是什么,此时会看到下边的代码:
在这里插入图片描述
我们可以看到,在调用invokeWithinTransaction()方法时,最后一个参数传进去的是invocation::proceed,说白了就是将拦截器的核心实现作为入参传递给了invocation,而所谓的核心实现,其实就是下边这个proceed()方法,如下图:
在这里插入图片描述
也就是说,执行invokeWithinTransaction()方法中的retVal = invocation.proceedWithInvocation()这行代码时,其实就会调用到ReflectiveMethodInvocation中的proceed()方法。而此时如果满足条件的话,就会通过invokeJoinpoint()方法来执行目标方法了,这个源码的细节在AOP源码分析已经讲过了。我们知道,由于执行目标方法这行代码,做了try catch处理,所以会根据执行目标方法是否发生异常,来做不同的处理。我们先假设此时没有发生异常,那么这个时候就会执行提交事务的操作,如下图:
在这里插入图片描述
我们现在知道了,在开启事务的时候,本质就是通过Connection来完成的,那么这里提交事务的时候必然也是通过Connection来完成的。我们还是深入这个commitTransactionAfterReturning()方法,来看一下,最终代码回到这个里面:
在这里插入图片描述
可以看到,提交事务时,是通过Connection来完成的。
如果发生异常的话,会导致事务回滚,如下图:
在这里插入图片描述
那么经过代码跟进,我们最终会看到下边这行代码,如下图:
在这里插入图片描述
可以看到,回滚事务时,同样是通过Connection来完成的。

一张图来梳理下今天讲的内容:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

youngerone123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值