Spring源码系列-Spring事务

目录

声明式事务

事务传播行为

源码解析

开启事务

调用顺序

@EnableTransactionManagement注解的两个作用

引入AutoProxyRegistrar后置处理器

引入ProxyTransactionManagerConfiguration配置类

加载切面

事务的Advisor的注册

事务Advice

事务PointCut

创建动态代理

调用代理方法


声明式事务

  • Spring事务,是通过数据库连接来实现的,当前线程中保存了一个map:key是数据源、value是数据库连接
  • 我们说的同一个事务,其实指的是同一个数据库连接,只有拥有同一个数据库连接才能同时提交和回滚
  • 如果在不同的线程,拿到的数据库连接肯定是不一样的,那么肯定也就是不同的事务,所以不要在事务中开启另外的线程去处理业务逻辑,这样会导致业务失效

Spring的事务和Spring AOP原理是差不多的,唯一的不同是,Spring AOP的增强逻辑需要我们程序员自己手动的定义各种Advice,但是spring事务的增强逻辑是spring自己内置提前写好的

事务传播行为

此时,第28行会更新失败,而第30行因为在父事务的内部又创建了一个子事务,所以第30行会更新成功

  • 一般情况下,第36行的方法需要另起一个类,否则spring不会帮我们重新创建一个新事务(也就是不会重新帮我们执行增强逻辑,在spring事务场景下,执行增强逻辑就是创建新事务)
  • 但是,在当前情况下,为什么没有另起一个类依然创建好了一个新的事务,这是因为第30行,AopContext.currentProxy()拿到了暴露在当前线程中的已经包含了增强逻辑的动态代理对象

这是因为JDK动态代理,默认情况下,调用本类的另外的方法,不会重复的执行增强逻辑,不会重复的执行增强逻辑意味着不会重复的创建新的事务

想使用AopContext.currentProxy(),这里就必须开启红框中的配置

不激活aop的注解,也能使用声明式事务,但是就无法暴露动态代理对象,也就无法通过AopContext的形式,显示拿到当前类的动态代理对象了

源码解析

开启事务

将MainConfig注册进AnnotatedConfigApplicationContext成为一个配置类,效果等价于给它加上@Configuration注解 

AbstractApplicationContext#refresh()中invokeBeanFactoryPostProcessor()中开始解析配置类的时候,就会去解析@Import注解,因为invokeBeanFactoryPostProcessor()内部会调用ConfigurationClassPostProcessor,ConfigurationClassPostProcessor回去解析配置类,而@Import注解就在配置类头上

默认就是PROXY,动态代理的方式

调用顺序

AbstractApplicationContext#refresh() ->invokeBeanFactoryPostProcessor() ->ConfigurationClassPostProcessor

ConfigurationClassPostProcessor解析配置类时,会去解析@Import注解,解析实现了ImportBeanDefinitionRegistrar接口的类,将实现了ImportBeanDefinitionRegistrar接口的类放入Map<ImportBeanDefinitionRegistrar,AnnotationMetadata>中

AutoProxyRegistrar实现了ImportBeanDefinitionRegistrar接口,所以AutoProxyRegistrar也会在Map<ImportBeanDefinitionRegistrar,AnnotationMetadata>中,所以这里,也会调起AutoProxyRegistrar#registerBeanDefinitions()中,也就是会调起下面的方法

AutoProxyRegistrar#registerBeanDefinitions()中,就会通过传进来的BeanDefinitionRegistry来向ioc容器中注册进一些BeanPostProcessor从而实现一些spring事务相关的功能

@EnableTransactionManagement注解的两个作用

引入AutoProxyRegistrar后置处理器

  • 解析切面
  • 创建动态代理

引入ProxyTransactionManagerConfiguration配置类

往IOC容器中事务相关的功能Bean,比如引入事务相关的增强Advisor

AutoProxyRegistrar#registerBeanDefinitions()中,就会通过传进来的BeanDefinitionRegistry来向ioc容器中注册InfrustructureAdvisorAutoProxyCreator这个BeanPostProcessor

注册事务的和注册AOP的后置处理器,使用的是同一个方法,并且在ioc容器中使用的名字都是一样的

比较aop的后置处理器和事务的后置处理器哪个优先级高,aop的后置处理器优先级更高,所以就会调用第129行,把beanClass给覆盖掉(因为事务的后置处理器先被执行进入ioc)

事务和AOP注解同时开启时,AOP的后置处理器,会覆盖掉事务的后置处理器

优先级,aop的后置处理器更高

后置处理器注册好后

就会在bean被实例化、属性注入、初始化后,来到

加载切面

AOP时,就是要在这里解析切面类,解析成为一个个的Advisor

事务时,当然也是要将创建事务的增强逻辑,解析成为一个Advisor

事务的Advisor的注册

ProxyTransactionManagerConfiguration这个也就是一个配置类,配置类中会通过@Bean引入很多实现事务功能的相关Bean,当前ProxyTransactionManagerConfiguration就是自动引入了事务的Advisor

  • 可以看到使用SpringBoot时,每引入一个小功能都有一个自己专属的Configuration配置类,每个专属配置类中都有自己相关的功能Bean,
  • 比如引入Redis时,就有Redis专属的配置类RedisAutoConfiguration
  • 比如引入Spring事务时,就有事务专属的ProxyTransactionManagerConfiguration配置类

事务Advice

后续调用下面的动态代理的pay()方法时,就会来上上面的invoke()方法来做一些事务方面的增强工作

事务PointCut

因为事务没有使用像aop的切点表达式来进行匹配,而是使用了@Transactional注解来做的匹配,只要你方法头上有@Transactional注解,那么就给你执行事务Advice中的增强逻辑创建新事务

TransactionAttributeSource,就是去扫描解析类的那些方法头上有@Transactional注解

  • 事务的Advisor是spring自己提供了,并自己注册进ioc容器的,
  • AOP的Advisor是需要项目启动时,直接解析出来的

事务aop和普通aop的不同点是

1. 普通aop的那些增强逻辑,都是用户通过@Before,@After等注解来自定义的。这些自定义的增强逻辑,需要spring通过后置处理器如解析它们,把它们解析成一个个得Advisor。

事务的增强逻辑是内置的,也就是spring自己写的。所以Spring就自己给我们写好了一个事务专有的Advisor,并注册到了ioc容器中。

2. 普通aop的匹配,是通过AspectJ的切点表达式来进行匹配,而事务看某个方法或者类是否命中了事务专有的Advisor,是通过解析@Transactional注解

1. aop是因为要解析切点表达式,来决定给那些bean生成动态代理对象。而事务就没那么复杂,只要看哪个类或者哪个类的方法上有@Transactional注解,就直接给它创建动态代理对象就好了。

2. 普通aop的解析切面,比较复杂,要把各种切面的注解解析成一个个Advisor。而事务的解析切面就简单了,Spring自己就提供了一个Advisor,都不需要去解析,直接就能拿到,拿到后事务的第一步解析切面的步骤就完成了

创建动态代理

如果使用第17行,那么使用这样的cglib动态代理时,在本类的一个方法中调用另一个方法,另一个方法也能有增强逻辑

而如果没有使用第17行,那么即便是使用了cglib动态代理时,在本类的一个方法中调用另一个方法,另一个方法也不会有增强逻辑

而spring事务的实现代码中,就算我们设置了proxyTargetClass为true,表示强制使用cglib动态代理,但是因为spring事务的实现代码没有使用上面第17行的调用方式,而是直接去调用了责任链,所以在本类的一个方法中调用另一个方法,另一个方法还是没有增强逻辑

调用代理方法

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/135295.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

编程知识\_C与汇编深入分析

1. 汇编怎么调用C函数 1.1 直接调用 bl main 1.2 想传参数怎么办&#xff1f; 在arm中有个ATPCS规则(ARM-THUMB procedure call standard&#xff08;ARM-Thumb过程调用标准&#xff09;。 约定r0-r15寄存器的用途&#xff1a; r0-r3 调用者和被调用者之间传参数 r4-r11 函…

理解王自如,希望成为王自如

我是卢松松&#xff0c;点点上面的头像&#xff0c;欢迎关注我哦&#xff01; 昨天看了王自如的采访视频&#xff0c;这两天刷了很多屏。 王自如说&#xff1a;我没看过格力给的工资条。在顶级的企业家身边工作&#xff0c;哪怕每天只是听她讲什么做什么&#xff0c;我都觉得是…

“富婆”通讯录——让你少奋斗50年

文章目录 一、项目需求分析二、通讯录各功能实现思路及代码准备工作2.1、打印一个菜单&#xff0c;提供用户选择功能2.2、添加联系人信息2.3、删除联系人信息2.4、查询联系人信息2.5、修改联系人信息2.6、显示所有联系人信息2.7、对所有联系人信息进行排序整理2.8、删除所有联系…

python速成

list类型中所有的方法(除sort之外)&#xff0c; 每一个方法附带一个实例&#xff1a;以及解释说明 append append(self, object, /) Append object to the end of the list. clear clear(self, /) Remove all items from list. 从列表中删除所有项目。 list_data [1,…

【开放视频+文档】Spinnaker多云持续部署实践

Hello, 首先&#xff0c;继续感谢大家持续的关注&#xff01; 这次我们已经将《Spinnaker实践》课程 实践文档课程笔记实验源码视频回放 全部免费开放给所有的技术人员。文档库视频基于语雀&#xff0c;扫描图片二维码可以获取语雀文档链接“https://www.yuque.com/devopsgr…

宋浩高等数学笔记(一)函数与极限

b站宋浩老师的高等数学网课&#xff0c;全套笔记已记完&#xff0c;不定期复习并发布更新。 章节顺序与同济大学第七版教材所一致。 目录 1.1映射与函数 1.2数列的极限 1.3函数的极限 1.4无穷小和无穷大 1.5极限运算准则 1.6极限存在准则and两个重要极限 1.7无穷小 1…

Java中的 向上转型 | 向下转型

目录 一.向上转型 直接赋值 总结&#xff1a; 通过传参 通过返回值 二.向下转型 instanceof 一.向上转型 向上转型其实就是创建一个子类对象&#xff0c;并将其当作父类对象来使用&#xff0c;一般语法格式如下&#xff1a; 父类类型 对象名 new 子类类型() 一般有以…

13. 高精度延时

13. 高精度延时 GPT 定时器简介GPT 定时器结构GPT 定时器工作模式 GPT 定时器相关寄存器GPTx_CRGPTx_PRGPTx_SRGPTx_CNTGPTx_OCR GPT 配置步骤程序编写bsp_delay.hbsp_delay.cmain GPT 定时器简介 GPT 定时器是一个 32 位向上定时器&#xff0c;也就是从0x00000000 开始向上递…

CCF ChinaSoft 2023 论坛巡礼 | CCF-华为胡杨林基金-形式化方法专项(海报)论坛

2023年CCF中国软件大会&#xff08;CCF ChinaSoft 2023&#xff09;由CCF主办&#xff0c;CCF系统软件专委会、形式化方法专委会、软件工程专委会以及复旦大学联合承办&#xff0c;将于2023年12月1-3日在上海国际会议中心举行。 本次大会主题是“智能化软件创新推动数字经济与社…

Java实现音频转码,WAV、MP3、AMR互转

1.背景 最近在集成一款产品支持语音双向对讲&#xff0c;首先是采集小程序的音频下发给设备端&#xff0c;然后可以控制设备录音生成音频链路让小程序播放。在这个过程中发现&#xff0c;设备除了AMR格式的音频外&#xff0c;其他的音频都不支持&#xff0c;而微信小程序有不支…

LangChain应用全解析

一、Langchain基础 1.Langchain简介 (1)替换模型 from langchain.prompts import ChatPromptTemplatechat ChatOpenAI(temperature0) 使用代理ip llm ChatOpenAI(model_name"gpt-3.5-turbo", max_tokens2048, temperature0.5,openai_api_keyapi_key,openai_ap…

docker stop slow 解决

验证 NanoMQ stop slow 的问题 daemon 和非 daemon 两种方式 docker stop 都很慢 疑问是默认情况下&#xff0c;SIGTERM 会被处理。 模拟 docker 内发送 SIGTERM 信号 # The default signal for kill is TERM # pkill will send the specified signal (by defau…

海康Visionmaster-环境配置:CSharp 二次开发环境配 置方法

C#二次开发环境的配置方法 以 WinForm 为例&#xff0c;进行 VM 二次开发的环境配置分为三步&#xff1a; 第一步&#xff0c;使用 VS 新建一个框架为.NET Framework 4.6.1 的工程&#xff0c;平台首选 32 位取消勾选&#xff0c;重新生成解决方案&#xff0c;保证工程 Debug 下…

c++ 信奥编程 1135:配对碱基链

#include<iostream> #include<cstdio> #include<cstring> using namespace std; int main(){char a[256];int len;int i;gets(a);lenstrlen(a);//计算字符串长度for(i0; i<len; i){ //输出配对碱基if(a[i]A) cout<<"T";if(a[i]T) cout<…

【java:牛客每日三十题总结-6】

java:牛客每日三十题总结 总结如下 总结如下 transient 变量和序列化有关&#xff0c;这是一个空接口&#xff0c;起标记作用&#xff0c;具体的序列化由ObjectOutputStream和ObjectInputStream完成。transient修饰的变量不能被序列化&#xff0c;static变量不管加没加transie…

C51--PC通过串口(中断)点亮LED

B4中的&#xff1a;REN允许 / 禁止串行接收控制位 REN 1为允许串行接收状态。 接收数据必须开启。所以SCON&#xff1a;0101 0000 &#xff1b;即0x50 如何知道数据已经接收 RI位&#xff1a;当收到数据后 RI 1&#xff08;由硬件置一&#xff09; 硬件置一后必须用软件…

开放领域问答机器人2——开发流程和方案

开放领域问答机器人是指在任何领域都能够回答用户提问的智能机器人。与特定领域问答机器人不同&#xff0c;开放领域问答机器人需要具备更广泛的知识和更灵活的语义理解能力&#xff0c;以便能够回答各种不同类型的问题。 开发开放领域问答机器人的流程和方案可以包括以下步骤…

Pytroch损失函数、反向传播和优化器、Sequential使用

Pytroch_Sequential使用、损失函数、反向传播和优化器 文章目录 nn.Sequential搭建小实战损失函数与反向传播优化器 nn.Sequential nn.Sequential是一个有序的容器&#xff0c;用于搭建神经网络的模块被按照被传入构造器的顺序添加到nn.Sequential()容器中。 import torch.nn …

[html] 动态炫彩渐变背景

废话不多说&#xff0c;直接上源码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>ZXW-NUDT: 动态炫…

交叉编译 openssl

要在 x86 平台上编译适用于 aarch64 架构的 OpenSSL 动态库&#xff0c;你需要使用交叉编译工具链。可以按照以下步骤进行&#xff1a; 安装 aarch64 交叉编译工具链&#xff1a; $ sudo apt-get install gcc-aarch64-linux-gnu g-aarch64-linux-gnu 这将安装 aarch64 交叉编…