【老王读Spring Transaction-1】从EnableTransactionManagement顺藤摸瓜,研究@Transactional的实现原理

news/2024/4/29 21:02:32/文章来源:https://blog.csdn.net/wang489687009/article/details/126623617

从EnableTransactionManagement顺藤摸瓜,研究@Transactional的实现原理

  • 前言
  • 版本约定
  • 正文
    • EnableTransactionManagement
    • ProxyTransactionManagementConfiguration——Spring 事务配置的核心类
    • TransactionInterceptor
    • TransactionAttributeSource
  • 小结

前言

Spring 对事务的封装是一个相对独立的功能,通过 spring-tx-5.3.9.jar 来进行支持。
里面的代码量也不大,我们完全可以像翻书的目录一样,浏览一下 spring-tx 的包结构和类,站在一个高的角度来审视一下 Spring 对事务的封装。

版本约定

spring-tx 5.3.9 (通过 SpringBoot 2.5.3 间接引入的依赖)

正文

浏览 spring-tx-5.3.9.jar ,我们大致可以挑出里面几个比较核心的类

springtxjar.png

org.springframework.transaction.annotation.Transactional  
org.springframework.transaction.annotation.EnableTransactionManagement  
org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration  org.springframework.transaction.interceptor.TransactionAspectSupport  
org.springframework.transaction.interceptor.TransactionInterceptor    
org.springframework.transaction.interceptor.TransactionAttribute  org.springframework.transaction.TransactionManager  
org.springframework.transaction.PlatformTransactionManager  
org.springframework.transaction.TransactionDefinition  
org.springframework.transaction.SavepointManager  

通常我们使用 Spring 的事务功能,都需要添加 @EnableTransactionManagement 来开启事务管理功能。
那就从 EnableTransactionManagement 开始看起

EnableTransactionManagement

@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {/*** 指定是否创建基于子类(CGLIB)的代理,而不是基于 jdk proxy 的代理。默认值为false。* 注意: 它是一个全局设置,设置为 true 将影响所有需要代理的 Spring 托管 bean,而不仅仅是那些标记为 @Transactional 的 bean。*/boolean proxyTargetClass() default false;AdviceMode mode() default AdviceMode.PROXY;int order() default Ordered.LOWEST_PRECEDENCE;}

可以看到,@EnableTransactionManagement 注解会引入 @Import(TransactionManagementConfigurationSelector.class)

注意: proxyTargetClass 是一个全局的配置。设置为 true 将影响所有需要代理的 Spring 托管 bean,而不仅仅是那些标记为 @Transactional 的 bean。

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {@Overrideprotected String[] selectImports(AdviceMode adviceMode) {switch (adviceMode) {case PROXY: // 默认是走这个分支return new String[] {AutoProxyRegistrar.class.getName(),ProxyTransactionManagementConfiguration.class.getName()};case ASPECTJ:return new String[] {determineTransactionAspectClass()};default:return null;}}private String determineTransactionAspectClass() {return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);}}

可以看到,TransactionManagementConfigurationSelector 会引入一个配置类: ProxyTransactionManagementConfiguration
ProxyTransactionManagementConfiguration 是 Spring 事务配置的核心类

ProxyTransactionManagementConfiguration——Spring 事务配置的核心类

@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {// 事务 Advisor,实现 Spring 切面事务的核心@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)@Role(BeanDefinition.ROLE_INFRASTRUCTURE)public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();advisor.setTransactionAttributeSource(transactionAttributeSource);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;}}

可以看到,这里面配置了一个 Advisor(Spring AOP 中的概念)——BeanFactoryTransactionAttributeSourceAdvisor

看到 Advisor 自然而然要想到它对应的 Pointcut 和 Advice

BeanFactoryTransactionAttributeSourceAdvisor 中设置的 Pointcut 和 Advice 分别是:

  • Pointcut: TransactionAttributeSourcePointcut
  • Advice: TransactionInterceptor

找到了 Pointcut,也就知道了它是怎么匹配 joinpoint 的。
找到了 Advice,也就知道了它在 joinpoint 上执行的 AOP 拦截逻辑是什么。(即: @Transactional 的实现逻辑)

对 Spring AOP 的 Advisor 还不清楚?建议阅读文章:Advice、Advisor、Advised都是什么接口

TransactionInterceptor

事务拦截器,是实现 Spring 事务拦截的核心类。

public Object invoke(MethodInvocation invocation) throws Throwable {// Work out the target class: may be {@code null}.// The TransactionAttributeSource should be passed the target class// as well as the method, which may be from an interface.Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);// Adapt to TransactionAspectSupport's invokeWithinTransaction...return invokeWithinTransaction(invocation.getMethod(), targetClass, new CoroutinesInvocationCallback() {@Override@Nullablepublic Object proceedWithInvocation() throws Throwable {return invocation.proceed();}@Overridepublic Object getTarget() {return invocation.getThis();}@Overridepublic Object[] getArguments() {return invocation.getArguments();}});
}

从源码中可以看到,业务方法的执行被封装在 MethodInvocation 中,事务的处理是放在 TransactionAspectSupport#invokeWithinTransaction() 方法中实现的。

TransactionAspectSupport.png

TransactionAttributeSource

用于获取事务元数据信息的接口。事务的元数据信息就包括: 使用的事务管理器、事务隔离级别、事务传播特性、事务超时时间、针对哪些异常进行回滚等

TransactionAttributeSource 获取到的事务元数据信息主要是提供给 TransactionInterceptor 来使用的。
TransactionAttributeSource 有多种实现,其中最常用的是 AnnotationTransactionAttributeSource,它主要用来处理注解类的事务元数据,即: @Transactional

TransactionAttributeSource.png

小结

Spring 对事务的封装是一个相对独立的功能,通过 spring-tx-5.3.9.jar 来进行支持。
Spring 注解事务是通过 AOP 来实现的。具体的实现是放在 TransactionInterceptor 这个 Advice 类中。

事务注解中的事务元数据信息的解析是通过 AnnotationTransactionAttributeSource 来处理的。


了解更多源码知识,请点击视频讲解:
SpringIoC源码由浅入深 : https://edu.51cto.com/sd/68e86


如果本文对你有所帮助,欢迎点赞收藏
有关 Spring 源码方面的问题欢迎留言一起交流…

公众号后台回复:下载IoC 或者 下载AOP 可以免费下载源码测试工程…

文章,请关注公众号: 老王学源码
gzh_b2.png

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

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

相关文章

【Linux】Rocky 9.0 Podman服务无法正常启动

Rocky Linux 9.0发布后&#xff0c;我在本地虚拟机对该版本进行了安装和测试&#xff0c;发现Podman服务在某些情况下&#xff0c;无法正常启动。 当/etc/selinux/config配置中&#xff0c;SELINUXenforcing为默认配置的时候&#xff0c;启动Podman服务&#xff0c;会出现下面的…

Vue3.0中使用路由进行跳转和传参以及取值

1、在vue2.0中的路由跳转 2、在vue2.0中取出路由的传值 在vue3.0中取消了vue2.0的部分api&#xff0c;新增的两个API,分别是useRouter和useRoute。 3、vue3.0中路由跳转 1&#xff09;第一步先引入import {useRouter} from vue-router; 2&#xff09;第二步 const router useR…

使用SSH反向转发服务器上的请求到个人电脑

开启服务器ssh网关功能 修改/etc/ssh/sshd_config文件&#xff0c;将GatewayPorts 修改为yes&#xff0c;并放开AllowAgentForwarding yes和AllowTcpForwarding yes&#xff0c;GatewayPorts默认为no&#xff0c;AllowAgentForwarding、AllowTcpForwarding默认被注释 修改完成…

数字逻辑设计(4)

文章目录数组逻辑设计&#xff08;4&#xff09;1. 组合逻辑电路中的险象一、门延迟二、逻辑冒险三、险象的分类1&#xff09;静态冒险2&#xff09;动态冒险3&#xff09;功能冒险2. 险象的判断及消除险象的判断1&#xff09;代数法2&#xff09; 卡诺图法险象的消除1&#xf…

paddlepaddle

项目用到了paddlespeech2&#xff0c;学了几天paddlepaddle&#xff0c;简单记录一下: 文章目录1 手写数字识别任务2 极简方案构建手写数字识别模型模型设计训练配置训练过程模型测试3【手写数字识别】之数据处理4【手写数字识别】网络结构4.1 经典的全连接神经网络4.2 卷积神经…

14天刷爆LeetCode算法学习计划——Day02双指针(2)

Day02——双指针一、前言二、知识点三、LeetCode189. 轮转数组1.题目2.解题示意图3.解题思路4.代码实现5.验证代码6.注意点四、结语一、前言 盲目刷题只会让自己心态爆炸&#xff0c;所以本期14天算法学习计划&#xff0c;也是LeetCode上的 [算法] 学习计划&#xff0c;在本专栏…

【LeetCode】统计全 1 子矩形(单调栈)

1504. 统计全 1 子矩形 - 力扣&#xff08;LeetCode&#xff09; 一、题目 给你一个 m x n 的二进制矩阵 mat &#xff0c;请你返回有多少个 子矩形 的元素全部都是 1 。 示例 1&#xff1a; 输入&#xff1a;mat [[1,0,1],[1,1,0],[1,1,0]] 输出&#xff1a;13 解释&#x…

TCL基础学习 字符串

基本指令 Tcl将所有的变量值视作字符串&#xff0c;并将他们作为字符串来保存。下标列出了比较有用的字符串操作命令&#xff1a; append将值追加到字符串尾binary二进制字符串操作format字符串格式化regexp正则表达式regsub用字符串模式进行字符串模拟匹配和替换scan字符串分…

计算机网络面试(一)网络分层结构

文章目录为什么使用分层结构OSI参考模型分层结构——OSI参考模型ISO各个分层解析TCP/IP各个分层解析为什么使用分层结构 对网络分层以后&#xff0c;可以将问题细化&#xff0c;使得问题更加容易分析。把一个大的系统分拆成小的体系后&#xff0c;便于在各个层次上制定标准&am…

《三叶虫与其他故事》我的恐惧如涟漪扩散,荡漾过百万年的时光

《三叶虫与其他故事》我的恐惧如涟漪扩散&#xff0c;荡漾过百万年的时光 布里斯D’J.潘凯克 Breece D‘J Pancake&#xff08;1952-1979&#xff09;&#xff0c;美国作家。二十六岁时自杀身亡&#xff0c;生前仅发表过六篇小说。潘凯克深受美国南方文学传统的影响&#xff0c…

3dmax的Corona的渲染器材质要如何完全转换VRay材质?

经常有伙伴问怎么转化材质&#xff0c;将CR转换成vr或者将VR转换CR~其实这一点需要通过材质转换插件即可转换~ 方法一&#xff1a;cr转vr材质&#xff0c;自带 第一步&#xff1a;确认自己的corona渲染器版本为corona5及以上&#xff1a; ​ 第2步 确认自己的vray渲染器版本…

springboot手机推荐网站毕业设计源码052329

摘 要 随着社会的发展&#xff0c;计算机的优势和普及使得手机推荐网站的开发成为必需。手机推荐网站主要是借助计算机&#xff0c;通过对首页、手机问答、公告消息、手机资讯、手机测评、我的、跳转到后台等信息进行管理。减少管理员的工作&#xff0c;同时也方便广大用户对个…

voip|网络电话,软件实现电信座机

原理 我们办理的宽带一般都含有座机服务&#xff0c;有一个座机号&#xff0c;自己买个座机插到光猫的语音口上就能用。光猫内置语音服务&#xff0c;座机通过电话线接上光猫来打电话&#xff0c;这个语音服务本质上是VOIP&#xff0c;基于IP的语音传输&#xff0c;光猫在VOIP…

Python输入漏洞利用(Python input漏洞)

背景条件 源码为python编写的程序该程序包含input函数&#xff0c;利用用户或自动化输入获取参数进行下一步 漏洞函数 input()&#xff1a;接收用户输入且不修改输入的类型raw_input()&#xff1a;接收用户输入并强制修改为字符串类型 漏洞源码示例 #!/usr/bin/python3 #-*- …

Revit中模板类图元使用后如何处理?

Revit中模板类图元使用后如何处理? 模板这类图元在使用结束后进行拆除的在正常建模形之后它就会一直存在虽然我们可以进行视图处理&#xff0c;但是新建立视图还会显示这类图元&#xff0c;我们可以用其他方法处理它么? 这里我们可以用阶段化来控制&#xff0c;这里以小别墅为…

通过配置文件修改docker容器端口映射

有时候&#xff0c;我们需要给正在运行的容器添加端口映射&#xff0c;百度一下发现很多都是通过iptables&#xff0c;或者是通过将当前容器通过docker commit命令提交为一个镜像&#xff0c;然后重新执行docker run命令添加端口映射。这种方法虽然可以&#xff0c;但是感觉好像…

java基于ssm课程建设制作服务平台系统

1.分管理员和客户,分别有注册账号,修改密码,等功能。2.管理员模块可以在不同的专业专栏上传视频,word文稿,并修改视频名,文稿,视频的增删功能,并给视频标注A B C三个等级3.用户可以在不同的专业专栏观看视频&#xff08;可以看到abc等级&#xff09;,可以下载管理员所上传文稿,…

【图解HTTP】HTTP协议基础

【HTTP协议用于客户端和服务器端之间的通信】 【客户端】请求访问文本或图像等资源的一段 【服务器端】提供资源响应的一端 客户端发送请求&#xff0c;服务器端回复响应 从客户端开始建立通信的&#xff0c;服务器端在没有接受到请求之前不会发送响应。 【请求报文】 【响…

Python 测试开发 20+ 项目实战,提升 5 大测试核心技能

⬇️ 点击“下方链接”,提升测试核心竞争力! >>更多技术文章分享和免费资料领取 软件测试行业从业门槛越来越高,传统手工测试人员逐渐被淘汰,而 测试开发工程师 则供不应求,成为 BAT 互联网大厂高薪求聘的稀缺人才,年薪 30W+ 起,年薪 50W-100W+ 也很常见,甚至超越…

【vue3】03. 跟着官网学习vue3

每日鸡汤&#xff1a;所有真实的快乐&#xff0c;都来自很久的努力 前言 这一节我们主要学习【模版语法】相关的知识&#xff0c;上一节&#xff0c;我们说到根目录下面的index.html是我们的根组件模版&#xff0c;所以可见模版语法是基于html的。 一、模版基本语法 1. 使用…