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

springBoot 事务基本原理

springBoot事务基本原理是基于spring的BeanPostProcessor,在springBoot中事务使用方式为:

一、在启动类上添加注解:@EnableTransactionManagement

二、在需要事务的接口上添加注解:@Transactional

基本原理:

注解:@EnableTransactionManagement  存在一个import  :

@Import(TransactionManagementConfigurationSelector.class)

TransactionManagementConfigurationSelector 继承树为:

 由此可以看到,TransactionManagementConfigurationSelector  继承自:

AdviceModeImportSelector
该类又实现了:
ImportSelector

 重写了接口:

	protected 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;}}

 AdviceMode :默认属性为:PROXY

 TransactionManagementConfigurationSelector:又导入了两个类,分别为:①AutoProxyRegistrar②ProxyTransactionManagementConfiguration

分析①AutoProxyRegistrar 该类实现接口:ImportBeanDefinitionRegistrar;通过registerBeanDefinitions 向容器中注入了组件,添加后置处理器

	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;}}}}if (!candidateFound && logger.isInfoEnabled()) {String name = getClass().getSimpleName();logger.info(String.format("%s was imported but no annotations were found " +"having both 'mode' and 'proxyTargetClass' attributes of type " +"AdviceMode and boolean respectively. This means that auto proxy " +"creator registration and configuration may not have occurred as " +"intended, and components may not be proxied as expected. Check to " +"ensure that %s has been @Import'ed on the same class where these " +"annotations are declared; otherwise remove the import of %s " +"altogether.", name, name, name));}}

向容器注入组件:InfrastructureAdvisorAutoProxyCreator

	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;}//注册一个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;}

主要添加一个bean的后置处理器:InfrastructureAdvisorAutoProxyCreator

	@Nullablepublic static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) {return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);}

InfrastructureAdvisorAutoProxyCreator 继承类图可见:

SmartInstantiationAwareBeanPostProcessor  -》InstantiationAwareBeanPostProcessor-》BeanPostProcessor

 

在类:AbstractAutoProxyCreator  重写了postProcessBeforeInitialization和postProcessAfterInitialization接口,其中after接口定义如下:

	public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {if (bean != null) {Object cacheKey = getCacheKey(bean.getClass(), beanName);if (this.earlyProxyReferences.remove(cacheKey) != bean) {return wrapIfNecessary(bean, beanName, cacheKey);}}return bean;}//创建代理对象//参数:当前bean,bean名称protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {return bean;}if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {return bean;}if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}//判断是否需要创建代理对象,如果需要则创建代理对象.Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);if (specificInterceptors != DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE);Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));this.proxyTypes.put(cacheKey, proxy.getClass());return proxy;}this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}
 

②:ProxyTransactionManagementConfiguration 是一个配置类,用于注册启用基于代理的注释驱动的事务管理所必需的 Spring 基础结构 bean。注册了三个bean,分别是:

1):BeanFactoryTransactionAttributeSourceAdvisor:事务通知器

	@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;}

2):TransactionAttributeSource:一个事务属性相关来源,知道如何获取事务属性,无论是从配置、源代码级别的元数据属性(如注释)还是其他任何位置,解析注解的属性

	@Bean@Role(BeanDefinition.ROLE_INFRASTRUCTURE)public TransactionAttributeSource transactionAttributeSource() {return new AnnotationTransactionAttributeSource();}

3):TransactionInterceptor:事务拦截器,具体执行事务的相关内容就在此处。

	@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;}

执行事务操作就在这个拦截器里面:

	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@Nullable//重点在这咧public Object proceedWithInvocation() throws Throwable {return invocation.proceed();}@Overridepublic Object getTarget() {return invocation.getThis();}@Overridepublic Object[] getArguments() {return invocation.getArguments();}});}

执行事务调用代码:

		PlatformTransactionManager ptm = asPlatformTransactionManager(tm);final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {// 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.//执行被代理的方法retVal = invocation.proceedWithInvocation();}catch (Throwable ex) {// target invocation exception//如果有异常就执行回滚completeTransactionAfterThrowing(txInfo, ex);throw ex;}finally {//清空事务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;}

以上就是spring事务的简单基本原理,不过分深究。核心的核心就是spring的后置处理机制。包括:BeanFactoryPostProcessor和BeanPostProcessor这两个关键的后置处理机制,在初始化前后对bean进行扩展处理。

相关文章:

springBoot 事务基本原理

springBoot事务基本原理是基于spring的BeanPostProcessor&#xff0c;在springBoot中事务使用方式为&#xff1a; 一、在启动类上添加注解&#xff1a;EnableTransactionManagement 二、在需要事务的接口上添加注解&#xff1a;Transactional 基本原理&#xff1a; 注解&am…...

HBuilderX无线连接真机

说明 安装的是HBuilderX&#xff0c;不是HBuilder&#xff0c;adb.exe所在目录是 x:\HBuilderX\plugins\launcher\tools\adbs\ 里面可能有其他版本&#xff0c;用哪个都&#xff0c;建议使用最新的 配置 首先&#xff0c;将真机使用USB连接到电脑上。 在adb目录中启动命令…...

idea初学笔记

注:初学需安装idea专业版&#xff0c;方便学习使用idea运行内存配置从eclipse工具开发 转 idea工具开发&#xff0c;可设置idea快捷键同eclipse快捷键 file -> Settings -> Keymap -> 选择Eclipse -> OK设置idea项目整体编码格式file -> Settings -> Editor …...

C++核心编程<类和对象>(4)

C核心编程<类和对象>4.类和对象4.1封装4.1.1封装的意义封装的意义1封装的意义24.1.2struct和class区别4.1.3成员属性设置为私有4.2对象的初始化和清理4.2.1构造函数和析构函数1.1构造函数语法&#xff1a;类名(){}1.2析构函数语法&#xff1a; ~类名(){}4.2.2构造函数的分…...

编写http workshop脚本从网页缓存里解析音乐

前一篇文章 编写http workshop脚本从网站下载音乐 示范了如何使用HttpClient访问API,以及Json数据的解析; 今天我们通过解析一个网页展示如何使用内置的LibXml2的功能解析HTML,提取我们关心的内容。 这里随便搜了2个资源类的网站,竟然使用的格式是一模一样的: https://www…...

当数字孪生遇上轨道交通,会有什么新发展?

轨道交通是城市间互通互联的命脉&#xff0c;是当下人们出行的首要选择之一&#xff0c;也是我国“新基建”的重点建设对象。将城轨交通各链路系统及多类型服务&#xff0c;与空间感知、移动互联、云计算等技术深度融合&#xff0c;集中实现城市空间、城轨分布、城轨运行动态的…...

原理底层计划--分布式事务

分布式事务 mysql事务 我们通过show engines查询存储引擎&#xff0c;mysql一般为innodb, 为什么&#xff1f; 因为innodb支持事务是原因之一。 特性无非ACID 原子性&#xff0c;一致性&#xff0c;隔离性&#xff0c;持久性 一致性是最后追求的结果&#xff0c;也就保证了数…...

Hive总结

文章目录一、Hive基本概念二、Hive数据类型三、DDL,DML,DQL1 DDL操作2 DML操作3 DQL操作四、分区操作和分桶操作1、分区操作2、分桶操作五、Hive函数六、文件格式和压缩格式一、Hive基本概念 Hive是什么&#xff1f; Hive&#xff1a;由 Facebook 开源用于解决海量结构化日志的…...

docker环境下安装jenkins

前言 差点被Jenkins的插件搞麻了&#xff0c;又是依赖不对又是版本需要升级的&#xff0c;差点破口大骂了&#xff0c;还好忍住了&#xff0c;静下心来慢慢搞&#xff0c;终于搞通了。这里必须记录一下。 废话不多说&#xff0c;上来就是干&#xff0c;jenkins是干嘛用的&…...

Shifu基础功能:设备接入

如何修改设备接入的配置 1. 编辑edgedevice.yaml文件 接入设备前&#xff0c;您需要对edgedevice.yaml文件进行编辑。对于不同的协议&#xff0c;protocolSettings可根据协议进行进一步配置&#xff0c;详细配置请前往Shifu API参考。 ... connection: Ethernet address: …...

基于Java+SpringBoot+Vue+Redis+RabbitMq的鲜花商城

基于JavaSpringBootVueRedisRabbitMq的鲜花商城 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、…...

蓝桥杯真题(解码)小白入!

本来看这个题感觉很简单&#xff0c;不就是Ascall值换来换去嘛&#xff0c;其实也真的这样&#xff0c;但是对于小白来说&#xff0c;ascall根本记不住 题目说了&#xff0c;每个数不会重复超过9次&#xff08;这见到那多了&#xff0c;不然根本不会写&#xff09; 其次如何实现…...

并发包中的ConcurrentLinkedQueue和LinkedBlockingQueue有什么区别?

第20讲 | 并发包中的ConcurrentLinkedQueue和LinkedBlockingQueue有什么区别&#xff1f; 在上一讲中&#xff0c;我分析了 Java 并发包中的部分内容&#xff0c;今天我来介绍一下线程安全队列。Java 标准库提供了非常多的线程安全队列&#xff0c;很容易混淆。 今天我要问你的…...

分享四个前端Web3D动画库在Threejs中使用的动画库以及优缺点附地址

Threejs中可以使用以下几种动画库&#xff1a;Tween.js&#xff1a;Tween.js是一个简单的缓动库&#xff0c;可以用于在three.js中创建简单的动画效果。它可以控制数值、颜色、矢量等数据类型&#xff0c;并提供了多种缓动函数&#xff0c;例如线性、弹簧、强化、缓冲等等。区别…...

谷歌浏览器和火狐浏览器永久禁用缓存【一劳永逸的解决方式】

目录 前言 谷歌浏览器 方式一 方式二 火狐浏览器 前言 缓存对于开发人员来说异常的痛苦,很多莫名其妙的bug就是由缓存导致的,但当我们在网上查找禁用缓存的方式时,找到的方式大多数都是在开发者工具的面板中勾选禁用缓存的选项,但这种方式有个弊端就是需要一直打开这个…...

kibana查看日志

一、背景 kibana收集日志功能很强大&#xff0c;之前只是简单的使用&#xff0c;此次系统学习了解并分享一波 二、kibana查看日志的基本使用 1.选择查询的服务和日志文件 注意&#xff1a;每个应用配置了开发与生产环境&#xff0c;需要找到指定的应用 1.1选择对应的应用 1.…...

JS 异步接口调用介绍

JS 异步接口调用介绍 Js 单线程模型 JavaScript 语言的一大特点就是单线程&#xff0c;也就是说&#xff0c;同一个时间只能做一件事。这样设计的方案主要源于其语言特性&#xff0c;因为 JavaScript 是浏览器脚本语言&#xff0c;它可以操纵 DOM &#xff0c;可以渲染动画&a…...

5.深入理解HttpSecurity的设计

深入理解HttpSecurity的设计 一、HttpSecurity的应用 在前章节的介绍中我们讲解了基于配置文件的使用方式&#xff0c;也就是如下的使用。 也就是在配置文件中通过 security:http 等标签来定义了认证需要的相关信息&#xff0c;但是在SpringBoot项目中&#xff0c;我们慢慢脱离…...

opencv-python numpy常见的api接口汇总(持续更新)

前言 最近写代码总是提笔忘api&#xff0c;因为图像处理代码写的比较多&#xff0c;所以想着把一些常用的opencv的api&#xff0c;包括numpy的api做一个记录&#xff0c;后面再忘记的时候&#xff0c;就不用去google挨个搜索了&#xff0c;只需要在自己的博客中一查就全知道了…...

概率论小课堂:伯努利实验(正确理解随机性,理解现实概率和理想概率的偏差)

文章目录 引言I 伯努利试验1.1 伯努利分布(二项式分布)1.2 数学期望值(简称期望值)1.3 平方差(简称方差)1.4 标准差1.5 小结引言 假设买彩票中奖的概率是一百万分之一,如果要想确保成功一次,要买260万次彩票。你即使中一回大奖,花的钱要远比获得的多得多。 很多人喜…...

无法与IP建立连接,未能下载VSCode服务器

如题&#xff0c;在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈&#xff0c;发现是VSCode版本自动更新惹的祸&#xff01;&#xff01;&#xff01; 在VSCode的帮助->关于这里发现前几天VSCode自动更新了&#xff0c;我的版本号变成了1.100.3 才导致了远程连接出…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析

这门怎么题库答案不全啊日 来简单学一下子来 一、选择题&#xff08;可多选&#xff09; 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘&#xff1a;专注于发现数据中…...

Psychopy音频的使用

Psychopy音频的使用 本文主要解决以下问题&#xff1a; 指定音频引擎与设备&#xff1b;播放音频文件 本文所使用的环境&#xff1a; Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

用docker来安装部署freeswitch记录

今天刚才测试一个callcenter的项目&#xff0c;所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?

在大数据处理领域&#xff0c;Hive 作为 Hadoop 生态中重要的数据仓库工具&#xff0c;其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式&#xff0c;很多开发者常常陷入选择困境。本文将从底…...

vulnyx Blogger writeup

信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面&#xff0c;gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress&#xff0c;说明目标所使用的cms是wordpress&#xff0c;访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...

【C++进阶篇】智能指针

C内存管理终极指南&#xff1a;智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...

STM32HAL库USART源代码解析及应用

STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...

Ubuntu系统多网卡多相机IP设置方法

目录 1、硬件情况 2、如何设置网卡和相机IP 2.1 万兆网卡连接交换机&#xff0c;交换机再连相机 2.1.1 网卡设置 2.1.2 相机设置 2.3 万兆网卡直连相机 1、硬件情况 2个网卡n个相机 电脑系统信息&#xff0c;系统版本&#xff1a;Ubuntu22.04.5 LTS&#xff1b;内核版本…...