大家好,我是楼仔!,下面我会简单介绍一下 Spring 事务的基础知识,以及使用方法,然后直接对源码进行拆解。,不 BB,上文章目录。,
,需要搭建环境的同学,代码详见:https://github.com/lml200701158/program_demo/tree/main/spring-transaction,下面是 DB 数据和 DB 操作接口:,基础测试代码,testSuccess() 是事务生效的情况:,执行入口:,输出:,为了方便大家能更好看懂后面的源码,我先整体介绍一下源码的执行流程,让大家有一个整体的认识,否则容易被绕进去。,整个 Spring 事务源码,其实分为 2 块,我们会结合上面的示例,给大家进行讲解。
,第一块是后置处理,我们在创建 Louzai Bean 的后置处理器中,里面会做两件事情:,获取 Louzai 的切面方法:首先会拿到所有的切面信息,和 Louzai 的所有方法进行匹配,然后找到 Louzai 所有需要进行事务处理的方法,匹配成功的方法,还需要将事务属性保存到缓存 attributeCache 中。,创建 AOP 代理对象:结合 Louzai 需要进行 AOP 的方法,选择 Cglib 或 JDK,创建 AOP 代理对象。,
,第二块是事务执行,整个逻辑比较复杂,我只选取 4 块最核心的逻辑,分别为从缓存拿到事务属性、创建并开启事务、执行业务逻辑、提交或者回滚事务。,注意:Spring 的版本是 5.2.15.RELEASE,否则和我的代码不一样!!!,上面的知识都不难,下面才是我们的重头戏,让你跟着楼仔,走一遍代码流程。,
,
,这里需要多跑几次,把前面的 beanName 跳过去,只看 louzai。,
,
,进入 doGetBean(),进入创建 Bean 的逻辑。,
,进入 createBean(),调用 doCreateBean()。,
,进入 doCreateBean(),调用 initializeBean()。,
,
,
,
,如果看过我前面几期系列源码的同学,对这个入口应该会非常熟悉,其实就是用来创建代理对象。,
,这里是重点!敲黑板!!!,先获取 louzai 类的所有切面列表;,创建一个 AOP 的代理对象。,
,3.2.1 获取切面列表,
,这里有 2 个重要的方法,先执行 findCandidateAdvisors(),待会我们还会再返回 findEligibleAdvisors()。,
,
,
,
,依次返回,重新来到 findEligibleAdvisors()。,
,
,
,
,进入 canApply(),开始匹配 louzai 的切面。,
,这里是重点!敲黑板!!!,这里只会匹配到 Louzai.testSuccess() 方法,我们直接进入匹配逻辑。,
,如果匹配成功,还会把事务的属性配置信息放入 attributeCache 缓存。,
,
,
,
,
,
,我们依次返回到 getTransactionAttribute(),再看看放入缓存中的数据。,
,再回到该小节开头,我们拿到 louzai 的切面信息,去创建 AOP 代理对象。,
,3.2.2 创建 AOP 代理对象,创建 AOP 代理对象的逻辑,在上一篇文章(Spring AOP)讲解过,我是通过 Cglib 创建,感兴趣的同学可以关注公众号「楼仔」,翻一下楼仔的历史文章。,回到业务逻辑,通过 louzai 的 AOP 代理对象,开始执行主方法。,
,因为代理对象是 Cglib 方式创建,所以通过 Cglib 来执行。,
,
,
,
,这里是重点!敲黑板!!!,下面的代码是事务执行的核心逻辑 invokeWithinTransaction()。,
,3.3.1 获取事务属性,在 invokeWithinTransaction() 中,我们找到获取事务属性的入口。,
,从 attributeCache 获取事务的缓存数据,缓存数据是在 “2.2.1 获取切面列表” 中保存的。,
,3.3.2 创建事务,
,
,
,通过 doGetTransaction() 获取事务。,通过 startTransaction() 开启事务。,
,下面是开启事务的详细逻辑,了解一下即可。,最后返回到 invokeWithinTransaction(),得到 txInfo 对象。,
,3.3.3 执行逻辑,还是在 invokeWithinTransaction() 中,开始执行业务逻辑。,
,
,
,
,
,进入到真正的业务逻辑。,
,执行完毕后抛出异常,依次返回,走后续的回滚事务逻辑。,3.3.4 回滚事务,还是在 invokeWithinTransaction() 中,进入回滚事务的逻辑。,
,。,
,执行回滚逻辑很简单,我们只看如何判断是否回滚。,
,
,
,如果抛出的异常类型,和事务定义的异常类型匹配,证明该异常需要捕获。,之所以用递归,不仅需要判断抛出异常的本身,还需要判断它继承的父类异常,满足任意一个即可捕获。,
,到这里,所有的流程结束。,我们再小节一下,文章先介绍了事务的使用示例,以及事务的执行流程。,之后再剖析了事务的源码,分为 2 块:,先匹配出 louzai 对象所有关于事务的切面列表,并将匹配成功的事务属性保存到缓存;,从缓存取出事务属性,然后创建、启动事务,执行业务逻辑,最后提交或者回滚事务。
© 版权声明
文章版权归作者所有,未经允许请勿转载。