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

Spring源码之解决循环依赖 三级缓存

目录

三级缓存核心原理

循环依赖的解决过程

1. Bean A创建过程中提前曝光工厂

2. Bean B创建时发现依赖A,从缓存获取

3. Bean A继续完成初始化

三级缓存的作用总结

二级缓存为何不够解决缓存依赖?

三级缓存如何解决?

为什么不直接在实例化后创建代理?

总结


Spring通过三级缓存机制解决循环依赖问题,这与populateBean()方法密切相关。下面我用简化代码解释这个机制:

三级缓存核心原理

Spring在DefaultSingletonBeanRegistry中维护了三个重要的缓存:

// 一级缓存:存储完全初始化的单例bean
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);// 二级缓存:存储早期曝光的单例bean(未完全初始化)
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);// 三级缓存:存储单例工厂对象,用于创建早期曝光的bean
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

循环依赖的解决过程

当发生循环依赖时,Spring通过以下步骤解决:

1. Bean A创建过程中提前曝光工厂
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {// 1. 实例化Bean(调用构造函数)BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);// 2. 提前曝光一个ObjectFactory,用于解决循环依赖boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences);if (earlySingletonExposure) {addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}// 3. 填充属性(可能触发对Bean B的依赖)populateBean(beanName, mbd, instanceWrapper);// 4. 初始化Bean(调用init方法和AOP代理)exposedObject = initializeBean(beanName, exposedObject, mbd);return exposedObject;
}// 将工厂添加到三级缓存
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {synchronized (this.singletonObjects) {if (!this.singletonObjects.containsKey(beanName)) {this.singletonFactories.put(beanName, singletonFactory);this.earlySingletonObjects.remove(beanName);}}
}
2. Bean B创建时发现依赖A,从缓存获取

populateBean()处理B的依赖时:

protected Object resolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) {// 查找依赖的bean(假设这里是A)String dependencyName = descriptor.getDependencyName();// 从三级缓存中获取beanObject bean = getSingleton(dependencyName, false);return bean;
}// 从三级缓存中获取bean的核心方法
protected Object getSingleton(String beanName, boolean allowEarlyReference) {// 1. 先从一级缓存获取Object singletonObject = this.singletonObjects.get(beanName);// 2. 如果一级缓存没有且bean正在创建中if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {// 3. 从二级缓存获取singletonObject = this.earlySingletonObjects.get(beanName);// 4. 二级缓存没有且允许早期引用if (singletonObject == null && allowEarlyReference) {synchronized (this.singletonObjects) {// 5. 从三级缓存获取工厂ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {// 6. 通过工厂创建早期bean实例singletonObject = singletonFactory.getObject();// 7. 放入二级缓存this.earlySingletonObjects.put(beanName, singletonObject);// 8. 从三级缓存移除this.singletonFactories.remove(beanName);}}}}return singletonObject;
}
3. Bean A继续完成初始化

当B完成创建后,A继续完成自己的初始化:

// 完成Bean A的初始化
exposedObject = initializeBean(beanName, exposedObject, mbd);// 将完全初始化的bean放入一级缓存
addSingleton(beanName, exposedObject);protected void addSingleton(String beanName, Object singletonObject) {synchronized (this.singletonObjects) {this.singletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);this.earlySingletonObjects.remove(beanName);}
}

三级缓存的作用总结

  1. 一级缓存(singletonObjects):存储完全初始化的单例bean,可直接使用
  2. 二级缓存(earlySingletonObjects):存储早期曝光的bean(未完成初始化),用于解决循环依赖
  3. 三级缓存(singletonFactories):存储工厂对象,允许在需要时创建早期bean,并支持AOP代理

通过这种机制,Spring允许在bean尚未完全初始化时就将其引用暴露给依赖它的其他bean,从而解决循环依赖问题。注意:只有单例作用域的bean支持循环依赖,原型模式不支持。你的问题非常关键!实际上,二级缓存理论上可以解决循环依赖,但Spring依然使用三级缓存,主要出于AOP代理的考虑。我来详细解释:

二级缓存为何不够解决缓存依赖?

假设只有两级缓存:

  1. singletonObjects(完全初始化的bean)
  2. earlySingletonObjects(早期曝光的bean)

当出现循环依赖时,我们可以在实例化后直接将bean放入earlySingletonObjects。但这样会有一个问题:如果bean需要AOP代理,早期曝光的将是原始对象,而不是代理对象

举个例子:

// Bean A依赖B,Bean B依赖A
class A {@Autowired private B b;@Transactional public void doSomething() {} // 需要AOP代理
}class B {@Autowired private A a;
}

当A和B循环依赖时:

  1. A实例化后放入二级缓存(此时是原始对象)
  2. B创建时从二级缓存获取A的原始对象
  3. B完成创建,注入A的原始对象
  4. A继续初始化,创建代理对象

最终结果:B持有的是A的原始对象,而不是代理对象,导致AOP失效!

三级缓存如何解决?

Spring通过三级缓存引入了ObjectFactory,将AOP代理的创建延迟到真正需要早期引用时:

// 三级缓存:存储工厂对象,用于创建可能需要代理的早期bean
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);// 添加工厂到三级缓存
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));// 获取早期引用的方法(可能创建代理)
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {Object exposedObject = bean;if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;// 如果需要代理,这里会创建代理对象exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);}}}return exposedObject;
}

当B需要A的早期引用时:

  1. 从三级缓存获取ObjectFactory
  2. 通过工厂调用getEarlyBeanReference(),此时才决定是否创建代理
  3. 将结果(可能是代理对象)放入二级缓存

这样一来,B持有的就是A的代理对象,保证了AOP的正确性。

为什么不直接在实例化后创建代理?

你可能会问:为什么不直接在实例化A后就创建代理,然后放入二级缓存?这样不就不需要三级缓存了吗?

原因有两点:

  1. 性能优化:不是所有bean都需要代理,延迟到真正需要时再创建可以避免不必要的代理
  2. 顺序正确性:Spring的后置处理器执行顺序是有规范的。postProcessBeforeInitializationpostProcessAfterInitialization应该在bean初始化阶段执行,而不是实例化阶段。如果提前创建代理,会破坏这个顺序。

总结

二级缓存可以解决普通对象的循环依赖,但无法解决代理对象的循环依赖。三级缓存通过引入ObjectFactory,将代理创建延迟到真正需要早期引用时,既保证了AOP的正确性,又维持了后置处理器的执行顺序。这是Spring在循环依赖和AOP之间找到的精妙平衡点。

相关文章:

Spring源码之解决循环依赖 三级缓存

目录 三级缓存核心原理 循环依赖的解决过程 1. Bean A创建过程中提前曝光工厂 2. Bean B创建时发现依赖A&#xff0c;从缓存获取 3. Bean A继续完成初始化 三级缓存的作用总结 二级缓存为何不够解决缓存依赖&#xff1f; 三级缓存如何解决&#xff1f; 为什么不直接在…...

山东大学计算机图形学期末复习9——CG12上

CG12上 几何管线末端&#xff1a;顶点已组装成基本图元&#xff08;Primitives&#xff0c;如点、线、三角形&#xff09;。 主要任务&#xff1a; 裁剪&#xff1a;视锥体是一个三维空间区域&#xff08;由近裁剪面、远裁剪面和侧面组成&#xff09;&#xff0c;超出该区域的图…...

关于软件测试开发的一些有趣的知识

文章目录 一、什么是测试&#xff1f;二、为什么要软件测试软件测试三、测试的岗位有哪些四 、软件测试和开发的区别五、走测试岗位为什么还要学开发。4、优秀的测试人员具备的素质我为什么走测试岗位 一、什么是测试&#xff1f; 其实这个问题说简单也不简单&#xff0c;说难…...

在Solana上使用 Scaled UI Amount 扩展

本指南提供 Solana Web3.js (Legacy v 1.x) 和 Solana Kit (v 2.x) 版本。选择适当的选项卡以查看你首选库的代码片段和说明&#xff1a; Solana Web3.js (Legacy)Solana Kit 概述 Solana Token-2022 程序 引入了强大的扩展&#xff0c;增强了代币功能&#xff0c;使其超越了…...

线性表之数组与栈详解

线性表之数组与栈详解 前言一、数组&#xff08;Array&#xff09;1.1 数组的基本概念1.2 数组的实现与操作1.3 数组的应用场景1.4 数组的优缺点 二、栈&#xff08;Stack&#xff09;2.1 栈的基本概念2.2 栈的实现方式2.3 栈的应用场景 2.4 栈的优缺点 三、数组与栈的对比总结…...

车载以太网驱动智能化:域控架构设计与开发实践

title: 车载以太网驱动专用车智能化&#xff1a;域控架构设计与开发实践 date: 2023-12-01 categories: 新能源汽车 tags: [车载以太网, 电子电气架构, 域控架构, 专用车智能化, SOME/IP, AUTOSAR] 引言&#xff1a;专用车智能化转型的挑战与机遇 专用车作为城市建设与工业运输…...

【Redis】redis用作缓存和分布式锁

文章目录 1. 缓存1.1 Redis作为缓存1.2 缓存更新、淘汰策略1.3 缓存预热、缓存穿透、缓存雪崩和缓存击穿1.3.1 缓存预热&#xff08;preheating&#xff09;1.3.2 缓存穿透&#xff08;penetration&#xff09;1.3.3 缓存雪崩&#xff08;avalanche&#xff09;1.3.4 缓存击穿&…...

深度学习中独热编码(One-Hot Encoding)

文章目录 独热编码独热编码的作用独热编码的优点独热编码的缺点场景选择独热编码&#xff08;PyTorch实现&#xff09;替代方案 实际使用分析&#xff1a;对对象类型使用独热编码为什么使用独热编码是合适的&#xff1f;&#x1f4cc; 场景说明&#xff1a;&#x1f4cc; 为什么…...

如何根据竞价数据判断竞价强度,是否抢筹等

竞价强度判断方法 价格变化幅度 观察开盘价与前一交易日收盘价的差距 &#xff1a;如果一只股票在开盘集合竞价阶段价格大幅高于前一交易日收盘价&#xff0c;说明市场对该股票的预期较为积极&#xff0c;可能有资金在主动抬高价格&#xff0c;这是一种较强的竞价强度表现。例如…...

Codex与LangChain结合的智能代理架构:重塑软件开发的未来

🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 引言:当代码生成遇见智能决策 想象以下场景: 凌晨三点:你需要紧急修复一个遗留系统的内存泄漏漏洞,但代码注释缺失且逻辑复杂; 产品经理需求变更:要求在24小时内将现有…...

2025年PMP 学习十八 第11章 项目风险管理 (11.5~11.7)

2025年PMP 学习十八 第11章 项目风险管理 &#xff08;11.5~11.7&#xff09; 第11章 项目风险管理 序号过程过程组1规划风险管理规划2识别风险规划3实施定性风险分析规划4实施定量风险分析规划5规划风险应对执行6实施风险应对执行7监控风险监控 文章目录 2025年PMP 学习十八…...

2025年PMP 学习十七 第11章 项目风险管理 (11.1~11.4)

2025年PMP 学习十七 第11章 项目风险管理 &#xff08;11.1~11.4&#xff09; 第11章 项目风险管理 序号过程过程组1规划风险管理规划2识别风险规划3实施定性风险分析规划4实施定量风险分析规划5规划风险应对执行6实施风险应对执行7监控风险监控 文章目录 2025年PMP 学习十七…...

impala

Impala&#xff0c;它是 Cloudera 开发的开源 实时 SQL 查询引擎&#xff0c;专为 Hadoop 设计。与 Presto 类似&#xff0c;Impala 用于交互式分析&#xff0c;但架构和设计理念有所不同。以下是 Impala 的核心特点和工作原理&#xff1a; 一、Impala 核心架构 1. 组件组成 …...

湖北理元理律师事务所:债务优化中的双维支持实践解析

在债务压力与生活质量失衡的社会议题下&#xff0c;法律服务机构的功能边界正在从单一的法律咨询向复合型支持延伸。湖北理元理律师事务所通过“法律心理”双维服务模式&#xff0c;探索债务优化与生活保障的平衡路径&#xff0c;其方法论或为行业提供实践参考。 法律框架&…...

Redis设计与实现——Redis命令参考与高级特性

Redis命令参考 数据类型相关命令 SET&#xff1a;设置键值&#xff0c;支持过期时间、不存在/存在条件。GET&#xff1a;获取键值&#xff0c;若键不存在返回 nil。INCR/DECR&#xff1a;将键的整数值增1/减1&#xff0c;键不存在时初始化为0。MSET/MGET&#xff1a;批量设置…...

TCP/UDP协议原理和区别 笔记

从简单到难吧 区别就是TCP一般用于安全稳定的需求&#xff0c;UDP一般用于不那么需要完全数据的需求&#xff0c;比如说直播&#xff0c;视频等。 再然后就是TPC性能慢于UDP。 再然后我们看TCP的原理&#xff08;三次握手&#xff0c;数据传输&#xff0c;四次挥手&#xff0…...

JavaScript基础-对象的相关概念

在JavaScript中&#xff0c;对象是核心的数据结构之一&#xff0c;几乎所有的高级功能都围绕着对象展开。理解对象的基本概念、创建方法以及操作方式对于掌握JavaScript至关重要。本文将详细介绍JavaScript中对象的相关概念&#xff0c;包括对象的定义、属性的操作、原型链和面…...

如何通过交流沟通实现闭环思考模式不断实现自身强效赋能-250517

感谢一直以来和我交流沟通的朋友们。 闭环思考 文字部分&#xff08;25-05-04&#xff09;这一天是青年节&#xff0c;在这一天与青年朋友交流这个是事先规划好的&#xff1a; “可以猜一猜&#xff0c;博士会被撤销吗&#xff1f;导师会被处理吗&#xff1f;千万不要回复&…...

震荡指标工具

一、引言 - 可视化数字烛台工具是对传统蜡烛图的补充&#xff0c;旨在帮助交易者更有效地进入和退出交易&#xff0c;提高交易利润。 - 通过分析蜡烛图&#xff0c;结合烛台震荡指标&#xff0c;提出了一个辅助视觉工具来辅助交易决策。 二、烛台指标与交易策略 -图表通过平均开…...

【自然语言处理与大模型】大模型(LLM)基础知识④

&#xff08;1&#xff09;微调主要用来干什么&#xff1f; 微调目前最主要用在定制模型的自我认知和改变模型对话风格。模型能力的适配与强化只是辅助。 定制模型的自我认知&#xff1a;通过微调可以调整模型对自我身份、角色功能的重新认知&#xff0c;使其回答更加符合自定义…...

返回码的方案对比和思考

前言 一般我们定义 Restful 接口返回码&#xff0c;常见的就是 const 定义 code &#xff0c; StatusToText() 来实现定义 msg&#xff0c; 在封装1 ~ 2个返回方法&#xff08;success、error&#xff09;就可以实现&#xff0c;只是突然想到这样设计是违反开闭原则的&#xf…...

Flink 的任务槽和槽共享

在 Apache Flink 中&#xff0c;任务槽&#xff08;Task Slot&#xff09; 和 槽共享组&#xff08;Slot Sharing Group&#xff09; 是资源管理和任务调度的关键机制。它们决定了 Flink 如何在集群中分配资源并执行任务。 一、任务槽&#xff08;Task Slot&#xff09; 1. 定…...

实验七 基于Python的数字图像水印算法

一、实验目的 掌握图像水印的应用&#xff1b; 掌握我国版权保护的发展现状&#xff1b; 掌握常见的数字图像水印算法。 二、实验内容 学习内容补充&#xff1a; 数字水印的鲁棒性评价主要采用含水印图像提取出的水印与原始水印的相似程度,使用归一化相关(NC&#xff0c;Nor…...

C语言:在 Win 10 上,gcc 如何编译 gtk 应用程序

在 Windows 10 上使用 g&#xff08;或 gcc&#xff09;编译基于 GTK 的 C 语言程序是完全可行的&#xff0c;且相比 Tcc 更为推荐&#xff0c;因为 g&#xff08;GNU 编译器套件&#xff09;对 GTK 的支持更加完善&#xff0c;配置也更简单。以下是详细步骤和注意事项&#xf…...

Vue.js---watch 的实现原理

4.7 watch 的实现原理 watch本质上就是使用了effect以及options.scheduler 定义watch函数&#xff1a; // watch函数:传入参数source以及回调函数function watch(source , cb) {effect(() > source.foo,{scheduler(){// 回调函数cb()}})}watch接收两个参数分别是source和c…...

Linux_ELF文件

目录 前言&#xff1a; 一、ELF文件的类型 二、ELF文件的组成格式 1. ELF头部(ELF Header) 2. 节头表(Section Header Table) 3. 程序头表(Program Header Table) 4. 节(Sections)与段(Segments) 三、ELF文件从形成到加载轮廓 1、ELF可执行文件形成过程 2、 可执行文…...

磁盘I/O子系统

一、数据写入磁盘流程 当执行向磁盘写入数据操作的时候&#xff0c;会发生如下的一系列基本操作。假设文件数据存在于磁盘扇区上&#xff0c;并且已经被读入到页缓存中。 进程使用write()系统调用写入文件。内核更新映射到文件的page cache。内核线程pdflush负责把页缓存刷入…...

【2025 技术指南】如何创建和配置国际版 Apple ID

想要体验更丰富的应用生态、使用国际版专属服务&#xff0c;或访问更多开发者工具&#xff1f;一个国际版 Apple ID 能帮你实现这些需求。本教程将详细介绍如何注册国际版 Apple ID 并正确配置支付信息&#xff0c;全程操作简单&#xff0c;适合开发者和技术爱好者参考。 一、准…...

C++(20): 文件输入输出库 —— <fstream>

目录 一、 的核心功能 二、核心类及功能 三、核心操作示例 1. 文本文件写入&#xff08;ofstream&#xff09; 2. 文本文件读取&#xff08;ifstream&#xff09; 3. 二进制文件操作&#xff08;fstream&#xff09; 四、文件打开模式 五、文件指针操作 六、错误处理技巧…...

05、基础入门-SpringBoot-HelloWorld

05、基础入门-SpringBoot-HelloWorld ## 一、Spring Boot 简介 **Spring Boot** 是一个用于简化 **Spring** 应用初始搭建和开发的框架&#xff0c;旨在让开发者快速启动项目并减少配置文件。 ### 主要特点 - **简化配置**&#xff1a;采用“约定优于配置”的原则&#xff0c;减…...

深入理解指针(6)

目录 1 sizeof和strlen的对⽐ 1.1 sizeof ​编辑1.2strlen 1.3 sizeof 和 strlen的对⽐ 2 数组和指针笔试题解析 2.1 ⼀维数组 ​编辑 2.2 字符数组 3 指针运算笔试题解析 3.1 题⽬1&#xff1a; ​编辑3.2 题目2 3.3 题目3 3.4 题目4 3.5 题目5 3.6 题目6 3.7…...

力扣HOT100之二叉树:108. 将有序数组转换为二叉搜索树

这道题之前做过&#xff0c;思路又给忘了&#xff0c;这道题用递归做是最简单的。 由于得到的数组是有序的&#xff0c;我们只需要取出中间位置的元素medium作为根节点&#xff0c;然后medium左边的剩余元素组成根节点的左子树&#xff0c;medium右边的剩余元素组成根节点的右子…...

手撕I2C和SPI协议实现

手撕I2C和SPI协议实现 目录 I2C协议原理I2C位操作实现I2C驱动代码编写SPI协议原理SPI位操作实现SPI驱动代码编写 I2C协议原理 I2C&#xff08;Inter-Integrated Circuit&#xff09;是一种串行通信总线&#xff0c;使用两根线&#xff1a;SCL&#xff08;时钟线&#xff09…...

452. Minimum Number of Arrows to Burst Balloons

题目描述 这道题用leetcode官方的解答反而搞复杂了。本题其实就是求重叠区间的交集。先按照区间左端点从小到大排序。然后拿出第一个区间作为【当前区间交集】的初始值。遍历后面的区间看那个区间和【当前交集】是否有重叠。如果有重叠则将【当前交集】和【当前区间】求交集并更…...

React 中,闭包陷阱

文章目录 前言1. 经典闭包陷阱示例过期状态问题 2. 解决方案2.1 正确声明依赖数组2.2 使用 useRef 捕获最新值**2.3 使用函数式更新&#xff08;针对状态更新&#xff09;****2.4 使用 useCallback 冻结闭包** **3. 异步操作中的闭包陷阱****事件监听示例** **4. 自定义 Hooks …...

代码复现5——VLMaps

项目地址 1 Setup # 拉取VLMaps仓库,成功运行后会在主目录生成文件夹vlmapsgit clone https://github.com/vlmaps/vlmaps.git#通过 conda 创建虚拟环境conda create -n vlmaps python=3.8 -yconda activate vlmaps #激活环境cd vlmaps # 切换到项目文件下bash install.ba…...

qt6 c++操作qtableview和yaml

保存qtableview数据到yaml文件从yaml文件读取数据到qtableview qtableview在UI界面拖放。 代码是问chat百度的深度探索。 - name: a1address: db1.dbw10type: int - name: a2address: db1.dbx1.0type: bool写到yaml&#xff0c;写前检查 bool plot1::isRowValid(const QStan…...

使用UniApi调用百度地图API的需要注意的地方

目录 前言 一、百度开放平台 1、功能简介 2、地点搜索服务 3、按行政区划检索API 二、Uniapi集成百度API 1、API集成流程 2、访问接口的定义 3、业务调用集成 三、可能遇到的问题 1、指定输出格式无效 2、返回数据的总数 四、总结 前言 在之前的系列博客中&#xf…...

(9)python开发经验

文章目录 1 os.path.join()拼接路径2 条件变量3 添加临时环境变量 更多精彩内容&#x1f449;内容导航 &#x1f448;&#x1f449;Qt开发 &#x1f448;&#x1f449;python开发 &#x1f448; 1 os.path.join()拼接路径 os.path.join() 是 Python 中处理文件路径拼接的核心函…...

windows 10 做服务器 其他电脑无法访问,怎么回事?

一般我们会先打开win10自己的防火墙策略&#xff0c;但是容易忽略 电脑之间 路由器上的防火墙&#xff0c;此时也需要查看一下&#xff0c;可以尝试先关闭路由器防火墙&#xff0c;如果可以了&#xff0c;再 设置路由器上的防火墙规则。 将路由器的上网设置 改成 路由模式 &a…...

mysql中limit深度分页详细剖析【爽文】

目录 一 mysql中limit深度分页 1.1 背景描述 1.2 mysql深度分页很慢原因 1.2.1 mysql的sql执行流程 1.2.2 mysql的深度分页很慢原因 1.3 解决办法 1.3.1 覆盖索引 1.3.2 子查询 1.3.3 标签查询 1.3.4 分区表 一 mysql中limit深度分页 1.1 背景描述 Limit深度分页造…...

【C++ Qt】布局管理器

每日激励&#xff1a;“不设限和自我肯定的心态&#xff1a;I can do all things。 — Stephen Curry” &#x1f914;绪论​&#xff1a; 在Qt开发中&#xff0c;界面布局的合理设计是提升用户体验的关键。早期&#xff0c;开发者常采用绝对定位的方式摆放控件&#xff0c;即通…...

Windows系统永久暂停更新操作步骤

目录 Windows系统永久暂停更新操作步骤 打开运行窗口进入注册表编辑器 导航路径图示 新建并配置DWORD值 新建值操作图示数值设置图示 在系统设置中应用暂停 暂停选项图示 注意事项 打开运行窗口 按下键盘上的 Win键 R 组合键&#xff0c;调出“运行”对话框。 进入组策略编…...

Java IO流进阶实战详解(含文件读写、拷贝、加密、字符集)

本文基于 Java 原生 IO 流&#xff0c;从最基础的字节流到字符流&#xff0c;再到实战案例&#xff08;如文件夹拷贝、文件加密等&#xff09;进行逐步深入讲解。适合有一定 Java 基础、希望掌握文件读写操作的。 一、前言 Java IO&#xff08;输入输出&#xff09;是我们日常…...

JavaScript【7】BOM模型

1.概述&#xff1a; BOM&#xff08;Browser Object Model&#xff0c;浏览器对象模型&#xff09;是 JavaScript 中的一个重要概念&#xff0c;它提供了一系列对象来访问和操作浏览器的功能和信息。与 DOM&#xff08;Document Object Model&#xff09;主要关注文档结构不同&…...

STM32F10xx 参考手册

6. 什么是寄存器 本章参考资料&#xff1a;《STM32F10xx 参考手册》、《STM32F10xx数据手册》、 学习本章时&#xff0c;配合《STM32F10xx 参考手册》“存储器和总线架构”及“通用I/O(GPIO)”章节一起阅读&#xff0c;效果会更佳&#xff0c;特别是涉及到寄存器说明的部分。…...

使用instance着色

本节我们学习使用instance着色器进行着色 //拾取var handler new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);handler.setInputAction(function(movement){console.log(movement);var pickedObject viewer.scene.pick(movement.position);if(Cesium.defined(picke…...

MySQL——4、表的约束

表的约束 1、空属性2、默认值3、列描述4、zerofill5、主键6、自增长7、唯一键8、外键9、综合案例 真正约束字段的是数据类型&#xff0c;但是数据类型约束很单一&#xff0c;需要有一些额外的约束&#xff0c;更好的保证数据的合法性&#xff0c;从业务逻辑角度保证数据的正确性…...

Datawhale PyPOTS时间序列5月第3次笔记

下游任务的两阶段(two-stage) 处理 下载数据并预处理的程序&#xff1a; # ------------------------------- # 导入必要的库 # ------------------------------- import numpy as np import torch from benchpots.datasets import preprocess_physionet2012 from pypots.imp…...

初探Reforcement Learning强化学习【QLearning/Sarsa/DQN】

文章目录 一、Q-learning现实理解&#xff1a;举例&#xff1a;回顾&#xff1a; 二、Sarsa和Q-learning的区别 三、Deep Q-NetworkDeep Q-Network是如何工作的&#xff1f;前处理&#xff1a;Convolution NetworksExperience Replay 一、Q-learning 是RL中model-free、value-…...