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

Spring的三级缓存机制详解及深度剖析其必要性

一、Spring为什么需要三级缓存源码剖析Spring采用三级缓存机制来处理单例Bean的循环依赖主要是为了解决一个核心难题当循环依赖遇上AOP面向切面编程时如何保证最终注入到其他Bean的是且仅是唯一的代理对象。简单来说如果没有AOP两级缓存12或13就足以解决循环依赖引入第三级缓存是为了保证代码设计的单一职责原则和高扩展性让创建原始Bean与生成代理对象的职责分离代码更清晰、灵活。为了理解这一点我们先看看Spring的三级缓存各自是什么。️ 三级缓存一览缓存名称变量名存储内容解决问题阶段生命周期一级缓存singletonObjects完全初始化好的成品BeanBean初始化完成最终存放全局唯一二级缓存earlySingletonObjects提前暴露的原始Bean引用 (半成品)循环依赖发生且无AOP时临时使用用完即删三级缓存singletonFactoriesObjectFactory对象工厂生成代理对象应对AOP场景临时工厂用完即删以下是它们的详细定义一级缓存 (singletonObjects)存放的是已经经历了完整生命周期实例化、属性填充、初始化的“成品Bean”。这是业务代码最终使用的单例对象保证了全局唯一性。二级缓存 (earlySingletonObjects)存放的是“半成品Bean”或“早期Bean”。这些对象已经完成了内存分配实例化但尚未进行属性填充和初始化。它主要解决了AOP代理对象的唯一性问题。三级缓存 (singletonFactories)这是整个机制的关键存放的是ObjectFactory?类型的对象工厂。ObjectFactory是一个函数式接口调用其getObject()方法才能真正创建对象。它的核心作用是将Bean的创建实例化与代理的生成AOP逻辑分离实现了代码的单一职责和延迟初始化。️ 源码剖析Spring的相关逻辑主要在AbstractAutowireCapableBeanFactory和DefaultSingletonBeanRegistry类中。核心查找方法getSingleton的定义如下// 在 DefaultSingletonBeanRegistry 中定义NullableprotectedObjectgetSingleton(StringbeanName,booleanallowEarlyReference){// 1. 从一级缓存成品缓存获取ObjectsingletonObjectthis.singletonObjects.get(beanName);// 目标bean不存在且当前正在创建中- 可能发生了循环依赖if(singletonObjectnullisSingletonCurrentlyInCreation(beanName)){// 2. 从二级缓存早期引用缓存获取singletonObjectthis.earlySingletonObjects.get(beanName);// 二级缓存没有且允许提前引用if(singletonObjectnullallowEarlyReference){// 加锁确保线程安全synchronized(this.singletonObjects){// 双重检查防止并发问题singletonObjectthis.singletonObjects.get(beanName);if(singletonObjectnull){singletonObjectthis.earlySingletonObjects.get(beanName);if(singletonObjectnull){// 3. 从三级缓存获取 ObjectFactoryObjectFactory?singletonFactorythis.singletonFactories.get(beanName);if(singletonFactory!null){// 调用工厂的 getObject() 方法创建对象可能是AOP代理singletonObjectsingletonFactory.getObject();// 将创建好的对象放入二级缓存this.earlySingletonObjects.put(beanName,singletonObject);// 从三级缓存中移除该工厂this.singletonFactories.remove(beanName);}}}}}}returnsingletonObject;}第1步优先从一级缓存singletonObjects获取这是为了直接拿到最完整的成品Bean。第2步当发生循环依赖时目标Bean的创建流程被阻塞此时该Bean会处于“正在创建”的状态。isSingletonCurrentlyInCreation(beanName)的校验触发Spring便会向下检查二级缓存。第3步二级缓存未命中表示这是该Bean第一次被循环依赖引用此时Spring会从三级缓存获取对应的ObjectFactory并调用getObject()。这一步是AOP的“钩子”getObject()方法内会执行getEarlyBeanReference其中包含了AOP代理的创建逻辑。存入二级缓存为了确保对象唯一性它会将生成的singletonObject存入二级缓存并移除三级缓存。这意味着即使有多个Bean如C、D在循环依赖中依赖ASpring也只会首次通过三级缓存创建一次代理对象后续都直接从二级缓存获取同一个实例。最终生成当A完成初始化后会被存入一级缓存并移除二级缓存。 工作流程从依赖到解决以A→B→A为例开始创建ASpring实例化A得到一个原始对象A_raw并将其包装成ObjectFactory存入三级缓存singletonFactories。A发现依赖B开始对A进行属性填充时发现需要B于是转去创建B。开始创建BSpring创建B的原始对象B_raw同样将其包装成ObjectFactory存入三级缓存。B发现依赖A对B进行属性填充时发现需要A于是调用getSingleton去获取A。三级缓存触发getSingleton方法在一级、二级缓存找不到A但在三级缓存中找到了A的ObjectFactory。Spring调用factory.getObject()该方法内部逻辑会判断A是否需要AOP若需要则创建A_proxy若不需要则返回A_raw。缓存升级getSingleton方法将上一步得到的对象A_proxy或A_raw存入二级缓存earlySingletonObjects并移出三级缓存。这个对象随后被注入到B中。B完成剩余初始化后成为一个成品Bean存入一级缓存。A继续完成初始化Spring拿到注入的成品Bean B继续完成A的初始化。A的初始化完成后从二级缓存中取出其对象存入一级缓存并将二级缓存中A的记录移除。 核心解惑为什么二级缓存不够结合上面的流程二级缓存足以在无AOP时解决循环依赖。但既然可能有AOP就必须引入三级缓存原因在于从设计角度看AOP代理的生成时机通常是在Bean生命周期的最后阶段初始化后。如果强制要求在一个Bean被循环依赖引用时属性填充阶段就必须生成代理对象就破坏了Spring原有的生命周期和单一职责原则也就是**“调用时机”**的问题。从扩展性角度看ObjectFactory是一个通用的函数式接口它不仅仅能用于AOP还可以为其他BeanPostProcessor提供扩展点来处理“早期引用”。这为Spring未来的功能扩展留下了巨大的空间体现了框架设计的高瞻远瞩。从对象唯一性看如果只用三级缓存不用二级缓存每次调用factory.getObject()都会产生一个新对象无法保证单例。因此需要二级缓存来暂存唯一的实例这正是引入**“第二级缓存”**的核心作用。从技术实现看即使将代理对象的创建时机强行提前到实例化之后确实可行但这会牺牲设计的优雅和清晰度让代码变得难以维护和扩展。Spring选择三级缓存是在技术可行性与代码优雅性之间做出的最佳权衡。Spring为什么“非要”三级缓存不可了。它本质上是对代码设计原则的极致追求与现实场景解决方案的精妙平衡的产物。二、结合Spring为什么“非要”三级缓存不可再详细解释问题核心为什么二级缓存解决不了AOP循环依赖先明确一个事实如果没有AOP即不需要代理两级缓存一级二级就足够了。但是有了AOP一个Bean最终会变成一个代理对象这个代理对象是在Bean初始化initializeBean的最后一步通过BeanPostProcessor生成的。现在考虑循环依赖A依赖BB依赖AA有AOP。A实例化 - 原始对象A_raw存入二级缓存如果只有两级会存A_raw。A填充属性发现需要B - 去创建B。B实例化 - B原始对象B_raw。B填充属性发现需要A - 从缓存中获取A。关键是此时A还没有初始化完成还没执行AOP后置处理所以二级缓存中只有A_raw。B拿到了A_raw注入给自己。B完成初始化成为成品B没有AOP问题。回到A继续初始化。最后一步执行AOP生成A_proxy。问题来了B里面持有的A是A_raw而最终容器中真正的A是A_proxy。这就产生两个不同的A对象B调用A的方法时不会有AOP增强比如事务不生效。所以二级缓存会导致对象不一致。三级缓存如何解决三级缓存中存的是ObjectFactory它的getObject()方法会调用getEarlyBeanReference。这个getEarlyBeanReference方法允许BeanPostProcessor提前返回一个代理对象的引用如果需要AOP。流程变化A实例化 - 创建ObjectFactory里面封装了getEarlyBeanReference逻辑存入三级缓存注意此时没有生成代理只是工厂。A填充属性发现需要B - 创建B。B实例化填充属性时需要A - 调用getSingleton。一级缓存没有A二级缓存没有A因为A还没放进二级三级缓存有A的工厂 - 调用工厂的getObject()- 触发getEarlyBeanReference- 判断A需要AOP直接生成代理对象A_proxy提前生成。将A_proxy放入二级缓存earlySingletonObjects删除三级缓存。返回A_proxy给B。B拿到A_proxy注入完成初始化成为成品B。回到A继续初始化。最后一步initializeBean中也会生成代理对象但此时SmartInstantiationAwareBeanPostProcessor发现这个Bean已经在二级缓存中有代理了就不会重复生成直接返回二级缓存中的A_proxy。A完成初始化将A_proxy移入一级缓存删除二级缓存。最终B中持有的和容器中的是同一个A_proxy完美解决。一句话硬核总结三级缓存允许在循环依赖暴露早期引用时通过getEarlyBeanReference提前生成最终的代理对象如果必要从而保证所有地方引用的是同一个对象。二级缓存如果直接存原始对象就无法在早期阶段得到代理对象导致最终对象不一致。我们只看源码中的关键一行在AbstractAutowireCapableBeanFactory.doCreateBean中实例化Bean后会执行addSingletonFactory(beanName,()-getEarlyBeanReference(beanName,mbd,bean));这个getEarlyBeanReference就是生成代理或返回原对象的地方。而getSingleton中从三级缓存取出工厂并调用getObject()就触发了上面的逻辑。没有三级缓存就没有地方存放这个“能提前生成代理的工厂”。三、疑惑点 ?疑惑1为什么代理必须延迟到初始化最后一步疑惑2为什么早期暴露必须用工厂而不能直接暴露原始对象疑惑3二级缓存的作用和时机到底是什么疑惑1为什么代理AOP必须延迟到Bean初始化的最后一步才生成核心答案因为AOP代理需要依赖Bean的完整状态包括属性填充、初始化方法等来决定如何增强。详细解释在Spring中一个Bean的生命周期是严格的实例化new一个对象调用构造函数—— 此时对象刚出生所有属性都是null。属性填充通过反射或setter注入依赖的其他Bean如Autowired字段。初始化调用PostConstruct、InitializingBean.afterPropertiesSet()、init-method等自定义初始化逻辑。AOP代理生成通过BeanPostProcessor具体是AbstractAutoProxyCreator在初始化之后包装成代理对象。为什么不能提前生成代理因为AOP增强可能需要用到刚刚初始化的状态比如你要在一个方法上做Transactional事务增强这个方法的执行结果可能依赖于PostConstruct里准备的数据。如果代理在实例化后就生成那代理对象里包裹的还是原始对象但原始对象的初始化还没执行代理就无法感知最终状态。更根本的设计原则生命周期统一。Spring所有的BeanPostProcessor都约定在初始化阶段前后工作。如果AOP可以任意提前就会破坏整个扩展点的执行顺序导致其他BeanPostProcessor如属性注入、自动代理等的不可预知行为。代码证据在AbstractAutowireCapableBeanFactory.initializeBean中protectedObjectinitializeBean(StringbeanName,Objectbean,NullableRootBeanDefinitionmbd){// ... 执行Aware方法、各种BeanPostProcessor的前置处理 ...invokeInitMethods(beanName,bean,mbd);// 执行初始化// ... 执行BeanPostProcessor的后置处理这里才会生成AOP代理...returnwrappedBean;}AOP代理生成是在applyBeanPostProcessorsAfterInitialization中而该方法位于invokeInitMethods之后。这是硬编码的顺序意味着Spring强制要求所有Bean必须完成初始化之后才能被代理。疑惑2为什么早期暴露必须用工厂ObjectFactory而不能直接暴露原始对象核心答案为了满足“需要代理但代理尚未生成”这种矛盾场景。工厂提供了一种“按需提前生成代理”的机制而不破坏正常的生命周期。详细解释假设循环依赖发生时A依赖BB依赖AA处在“实例化完成但属性填充和初始化尚未完成”的阶段。此时如果有另一个BeanB需要A按正常流程B只能得到一个原始对象因为A的代理还没生成。但Spring希望如果A最终需要被代理那么B也应该拿到那个代理对象而不是原始对象。然而此时A的代理还没生成因为还没到初始化完成那一时刻怎么办→用一个工厂对象延迟决定工厂里封装了一个方法getEarlyBeanReference这个方法内部会去检查“这个Bean是否需要代理如果需要在现在循环依赖暴露时就生成代理”。这样一来Spring不用破坏生命周期代理生成时机仍然在初始化之后只是对循环依赖做了特例同时也能让B拿到正确的对象代理。为什么不直接暴露原始对象并标记“以后替换”如果直接暴露原始对象B已经引用了原始对象后续Spring无法把B里持有的引用偷偷换成代理对象Java是值传递换不了。所以必须在暴露的那一刻就让B拿到最终的、正确的对象——即使这个对象是通过提前生成的。为什么不直接在实例化后生成代理并一直使用如果AOP代理在实例化后立即生成那就不需要工厂了。但这样会破坏前面说的“初始化后才代理”的约定导致代理对象可能在未初始化时就暴露给外部调用方法时会出问题因为依赖的属性还是null。工厂模式的精妙之处通常情况下没有循环依赖工厂不会被调用代理会在初始化结束后正常生成。有循环依赖时工厂被调用提前生成代理但此时只是“提前生成了代理”而非“提前完成初始化”。代理对象内部的原始对象的初始化仍会按正常流程执行只是代理对象已经暴露了。这样既满足了循环依赖又最大限度地保持了生命周期的完整性。疑惑3二级缓存的作用和时机是什么核心答案二级缓存用于保证“同一个Bean在循环依赖暴露期间只通过三级工厂生成一次对象”避免重复创建代理或重复调用工厂。时机代码回顾DefaultSingletonBeanRegistry.getSingleton// 从三级缓存拿到工厂ObjectFactory?singletonFactorythis.singletonFactories.get(beanName);if(singletonFactory!null){// 生成对象可能是原始也可能是代理singletonObjectsingletonFactory.getObject();// 放入二级缓存this.earlySingletonObjects.put(beanName,singletonObject);// 删除三级缓存this.singletonFactories.remove(beanName);}作用分析如果没有二级缓存只有一级和三级那么当有两个Bean同时依赖于A时比如C依赖AD也依赖A流程会变成C请求A → 发现三级缓存有工厂 → 调用工厂生成对象比如代理对象A1→ 返回给C。D请求A → 发现三级缓存还有工厂因为C用完后没有删除如果没删除就会重复生成→ 再次调用工厂生成对象A2 → 返回给D。问题C和D拿到的不是同一个对象A破坏了单例。如果三级缓存用完后删除那D再次请求时三级缓存已空就会直接返回null导致D无法拿到A从而报错。所以需要一个地方存放“已经通过工厂生成过一次的对象”并且这个对象在A完全初始化之前对所有其他依赖者可见。这个存放的地方就是二级缓存。一旦生成就将对象移到二级缓存之后所有其他依赖A的Bean直接从二级缓存拿同一个实例。等到A完全初始化完成再将这个对象从二级缓存移到一级缓存成品区。为什么需要二级不能用一级直接存半成品因为一级缓存是专门存放“完全初始化好的成品”的如果半成品也放在一级会导致getSingleton无法区分是否已初始化完毕可能错误地获取到未初始化的对象。保持缓存的语义清晰非常重要一级成品二级早期暴露出的半成品可能已代理但未初始化三级工厂。把它们串起来——核心逻辑链代理生成时机正常情况下在初始化之后这是Spring的硬设计。循环依赖冲突在初始化之前就需要暴露Bean但暴露的应该是代理如果需要而不是原始对象。解决方案不直接暴露对象而是暴露一个工厂三级缓存在需要时由工厂决定生成原始对象还是提前生成代理。避免重复生成工厂生成的对象暂存于二级缓存确保多个依赖者拿到同一个实例。最终转移Bean完全初始化后从二级缓存移到一级缓存成品区。

相关文章:

Spring的三级缓存机制详解及深度剖析其必要性

一、Spring为什么需要三级缓存源码剖析 Spring采用三级缓存机制来处理单例Bean的循环依赖,主要是为了解决一个核心难题:当循环依赖遇上AOP(面向切面编程)时,如何保证最终注入到其他Bean的,是且仅是唯一的代…...

抖音内容智能采集工具:轻松实现视频、图集与音乐的高效下载

抖音内容智能采集工具:轻松实现视频、图集与音乐的高效下载 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback …...

前端传19位雪花ID给后端,为啥总查不到数据?手把手教你用Jackson搞定JS精度丢失

19位雪花ID在前端传递中的精度陷阱:从原理到解决方案的完整指南 最近在前后端分离项目中遇到一个诡异的问题:前端通过API传递的19位雪花ID,到了后端却总是查不到对应数据。经过排查发现,这背后隐藏着JavaScript数值精度限制的经典…...

STM32H750实战:用MPU给LCD屏和SDRAM划个安全区,解决屏幕闪烁和DMA数据错乱

STM32H750实战:MPU精准配置解决LCD闪烁与DMA数据错乱 1. 问题现象与根源分析 在STM32H750这类高性能MCU的开发过程中,工程师们经常会遇到一些令人困扰的现象:LCD屏幕出现随机闪烁、显示花屏,或者通过DMA传输的数据出现错乱。这些看…...

新手如何通过Taotoken快速获得第一个可用的AI大模型API Key

🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 新手如何通过Taotoken快速获得第一个可用的AI大模型API Key 对于希望将大模型能力集成到应用中的开发者而言,获取一个稳…...

HugeJsonViewer:专为GB级JSON大文件设计的专业查看解决方案

HugeJsonViewer:专为GB级JSON大文件设计的专业查看解决方案 【免费下载链接】HugeJsonViewer Viewer for JSON files that can be GBs large. 项目地址: https://gitcode.com/gh_mirrors/hu/HugeJsonViewer 在当今数据驱动的时代,开发者和数据分析…...

Day10_开源鸿蒙_Flutter_for_OpenHarmony_离线笔记_全量备份导出导入

开源鸿蒙 Flutter for OpenHarmony:离线笔记收官(全量备份导出/导入) 欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net 离线笔记做到 Day9,单条笔记已经能导出/导入(二维码复制文…...

从一条竖线到芯片级故障:记录一次Camera ISP模块的深度硬件debug之旅

从一条竖线到芯片级故障:记录一次Camera ISP模块的深度硬件debug之旅 当产线上百万分之一的故障率遇上工程师的直觉,往往能碰撞出最精彩的技术侦探故事。这次遇到的是一条看似简单的图像竖条纹——在百万台设备中仅出现一例,却意外揭开了芯片…...

告别连线噩梦:用SystemVerilog接口(interface)重构你的模块通信(附modport与时钟块实战)

告别连线噩梦:用SystemVerilog接口(interface)重构你的模块通信(附modport与时钟块实战) 在数字电路设计的进阶之路上,每个工程师都会遇到那个令人头疼的时刻——当模块间的信号连线从最初的几条膨胀到几十条,密密麻麻…...

AI 模型本地化部署

一、什么是 AI 模型本地化部署? 就是:把大模型 / AI 程序从云端服务器,搬到你自己的电脑、服务器、设备上运行。 特点: 不联网也能用数据不上传,隐私安全速度更快、无费用可完全自定义 常见用途: 本地…...

HMCL启动器跨平台架构深度解析:多系统兼容性实现与性能优化技术对比

HMCL启动器跨平台架构深度解析:多系统兼容性实现与性能优化技术对比 【免费下载链接】HMCL A Minecraft Launcher which is multi-functional, cross-platform and popular 项目地址: https://gitcode.com/gh_mirrors/hm/HMCL HMCL(Hello Minecra…...

GD32F103VET6替换STM32F103VET6实战:ADC+DMA读取内部温度传感器,从-400℃到正常值的排查全记录

GD32F103VET6替换STM32F103VET6实战:从ADC异常到LIN引脚干扰的深度排查 最近在将产品从STM32F103VET6迁移到GD32F103VET6时,遇到了一个令人困惑的问题:内部温度传感器读数异常,显示为-400℃左右的离谱数值。这个问题看似简单&…...

QKeyMapper终极指南:Windows平台全设备按键映射与虚拟手柄模拟的完全解决方案

QKeyMapper终极指南:Windows平台全设备按键映射与虚拟手柄模拟的完全解决方案 【免费下载链接】QKeyMapper [按键映射工具] QKeyMapper,Qt开发Win10&Win11可用,不修改注册表、不需重新启动系统,可立即生效和停止。支持游戏手柄…...

DeepSeek V4模型的Agent能力实测

DeepSeek V4 系列发布之后,关于它能不能用、好不好用的讨论很多,但大部分评测还停留在普通对话或编码上。CowAgent 作为一个开源中立的 Agent 框架,则更关心模型在 Agent 链路中的真实表现,包括任务规划、复杂编码、长期记忆、浏览…...

终极指南:3步实现Unity游戏实时翻译,打破语言障碍

终极指南:3步实现Unity游戏实时翻译,打破语言障碍 【免费下载链接】XUnity.AutoTranslator 项目地址: https://gitcode.com/gh_mirrors/xu/XUnity.AutoTranslator XUnity.AutoTranslator是一款专为Unity游戏设计的智能翻译插件,让你无…...

QueryExcel:如何在5分钟内从上百个Excel文件中找到你需要的数据?

QueryExcel:如何在5分钟内从上百个Excel文件中找到你需要的数据? 【免费下载链接】QueryExcel 多Excel文件内容查询工具。 项目地址: https://gitcode.com/gh_mirrors/qu/QueryExcel 在日常工作中,你是否曾经面对过这样的困境&#xf…...

Linux RT 调度器的 rt_mutex:实时互斥锁的优先级继承

简介在工业控制、自动驾驶、航天嵌入式、工控网关等硬实时场景中,Linux 原生普通互斥锁mutex存在致命短板:无法规避经典的优先级反转问题。低优先级任务持有锁阻塞中高优先级实时任务,高优先级任务又被普通分时任务抢占,系统实时响…...

从金融到政务:运维智能体行业落地实战与价值证明

最好的技术,一定能在真实场景中创造可量化价值。 Lerwee运维智能体已在金融、交通、制造、政务等行业规模化落地,服务 1000 客户,覆盖核心业务与关键基础设施。 本文选取四大标杆案例,还原真实痛点、架构设计、落地过程与价值成果…...

FigmaCN中文界面插件:3分钟免费实现Figma界面全中文化的终极指南

FigmaCN中文界面插件:3分钟免费实现Figma界面全中文化的终极指南 【免费下载链接】figmaCN 中文 Figma 插件,设计师人工翻译校验 项目地址: https://gitcode.com/gh_mirrors/fi/figmaCN 还在为Figma的英文界面而烦恼吗?专业术语看不懂…...

类脑计算融合物理机理,镜像视界实现孪生高效落地

类脑计算融合物理机理,镜像视界实现孪生高效落地——镜像视界新一代高效可信镜像孪生技术白皮书前言当前数字孪生与视频孪生行业,深陷落地成本高、建模周期长、算法不可信、规模化无望的深层困境,传统技术路线始终无法突破数据驱动黑盒、重型…...

3个步骤快速生成Beyond Compare 5密钥:完整授权激活终极方案

3个步骤快速生成Beyond Compare 5密钥:完整授权激活终极方案 【免费下载链接】BCompare_Keygen Keygen for BCompare 5 项目地址: https://gitcode.com/gh_mirrors/bc/BCompare_Keygen 你是否正在寻找一个简单可靠的方法来解除Beyond Compare 5的30天试用限制…...

终极硬件调优指南:如何用Universal x86 Tuning Utility轻松解锁Intel/AMD设备性能

终极硬件调优指南:如何用Universal x86 Tuning Utility轻松解锁Intel/AMD设备性能 【免费下载链接】Universal-x86-Tuning-Utility Unlock the full potential of your Intel/AMD based device. 项目地址: https://gitcode.com/gh_mirrors/un/Universal-x86-Tunin…...

《龙虾OpenClaw系列:从嵌入式裸机到芯片级系统深度实战60课》032、Bootloader设计——从Flash加载到固件升级

OpenClaw系列032:Bootloader设计——从Flash加载到固件升级 一、一次现场升级失败的血泪史 去年冬天,某客户现场设备批量变砖。现象很统一:上电后LED狂闪三次,然后死寂。远程抓日志,发现Bootloader在CRC校验阶段直接跳到了错误处理——0x1FFF0000的复位向量被读成了全0x…...

2026届最火的五大降重复率工具实际效果

Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 要降低AI生成文本的检测率,关键之处在于让内容展现出人类写作的典型特征&#xf…...

Python基础操作

基本操作方法 快捷键 ctrlK,ctrlC/U:注释以及解除注释 ctrl,:进入设置 ctrl~:打开命令行...

《龙虾OpenClaw系列:从嵌入式裸机到芯片级系统深度实战60课》031、设备树与硬件描述:从寄存器到设备模型的映射

031、设备树与硬件描述:从寄存器到设备模型的映射 一次让我熬夜到凌晨三点的设备树调试 去年做一款基于i.MX6ULL的工业控制器,外挂了一个SPI接口的ADC芯片——AD7689。硬件设计没问题,原理图确认了三遍,PCB打样回来焊接完,上电。结果呢?SPI读回来的数据全是0xFF。 我第…...

告别手动抢购!用Python+Selenium写一个淘宝/京东秒杀脚本(附完整代码和避坑指南)

PythonSelenium电商秒杀脚本实战:从环境搭建到精准执行的完整指南 每次电商大促时,手动抢购总让人手忙脚乱?作为Python开发者,我们可以用Selenium这个强大的浏览器自动化工具来提升效率。本文将带你从零开始构建一个合规、高效的…...

科技巨头隐私博弈:从商业模式到技术架构的十年演进

1. 从一篇旧文看科技巨头的“隐私游戏”:一场持续十余年的博弈2012年1月,Brian Bailey在EE Times上发表了一篇题为《What were they thinking: Google is at it again》的评论文章。这篇文章的核心,并非探讨某个具体的芯片设计工具或半导体工…...

AI赋能科研:构建模块化工作流,打造你的“第二大脑”

1. 项目概述:当AI成为科研的“第二大脑”如果你是一名科研工作者,无论是学生、研究员还是工程师,大概率都经历过这样的场景:面对海量的文献,感觉无从下手;处理复杂的实验数据,被重复性劳动消耗大…...

2023汽车网络安全报告:CVE激增150%,攻击影响扩大,生成式AI重塑攻防格局

1. 2023年汽车网络安全态势总览:一场永不停歇的攻防战干了十几年技术,从嵌入式到车联网,我越来越觉得,汽车行业现在最头疼的可能不是电池续航,也不是自动驾驶的算法,而是网络安全。这就像你给一辆车装上了最…...