Spring三级缓存机制深度解析:从循环依赖到AOP代理的源码级揭秘
1. 从一次诡异的Bean创建异常说起那天下午我正在调试一个看起来平平无奇的Spring Boot服务。服务启动时控制台突然抛出了一个异常不是常见的BeanCreationException而是一个更底层的、关于BeanCurrentlyInCreationException的错误错误信息里反复提到了“循环依赖”和“正在创建中”。这让我有点意外因为项目结构并不复杂理论上不应该出现这么明显的循环依赖问题。我检查了Bean的定义发现是两个Service之间互相Autowired了对方这确实是教科书式的循环依赖场景。但奇怪的是这个项目之前一直运行得好好的直到我引入了一个Async注解在其中一个Service的方法上问题才暴露出来。这个经历让我重新审视Spring处理循环依赖的机制。我们都知道Spring通过“三级缓存”解决了单例Bean的循环依赖问题这几乎是面试八股文的必考题。但当你真的在复杂场景下比如结合了AOP、Async、Transactional遇到问题时仅仅背出“一级缓存放成品Bean二级缓存放早期暴露对象三级缓存放ObjectFactory”是远远不够的。你需要真正理解每一级缓存存在的必要性、它们协同工作的时序以及这个精巧设计背后的权衡与边界。这次我们就抛开那些笼统的概念直接深入到DefaultSingletonBeanRegistry的源码里看看这三级缓存到底是如何在Bean的生命周期中“辗转腾挪”化险为夷的。2. 三级缓存的庐山真面目源码中的三个Map要理解三级缓存首先得找到它们藏在哪。在Spring IoC容器的核心——DefaultSingletonBeanRegistry类中定义了三个至关重要的Map这就是我们常说的三级缓存。它们不是任何配置而是Spring框架为解决单例Bean循环依赖而设计的内部数据结构。2.1 一级缓存singletonObjects– 成品的归宿/** Cache of singleton objects: bean name to bean instance. */ private final MapString, Object singletonObjects new ConcurrentHashMap(256);这是大家最熟悉的一级缓存也叫“单例池”。它的角色非常明确存放已经完全初始化好的、可供直接使用的成品Bean。当一个Bean走完了完整的生命周期实例化、属性填充、初始化它就会被放入这个singletonObjects中。之后任何地方通过getBean()方法请求这个Bean时容器会首先来这里查找。如果找到了直接返回这是性能最高、最直接的路径。你可以把它想象成一个餐厅的“出菜口”做好的菜都放在这里服务员直接从这里端给客人。2.2 二级缓存earlySingletonObjects– 半成品的临时驿站/** Cache of early singleton objects: bean name to bean instance. */ private final MapString, Object earlySingletonObjects new ConcurrentHashMap(16);二级缓存的存在是解决循环依赖的关键一环。它存放的是**“早期暴露”的Bean引用**。什么是早期暴露在Bean的生命周期中通常是在“实例化”调用构造方法创建出对象之后但在“属性填充”和“初始化”之前Spring会尝试将这个刚创建出来、还是个“空壳”的对象提前暴露出去。这个对象可能还没有注入依赖也没有执行PostConstruct方法但它已经是一个Java对象了。二级缓存就是这个提前暴露的对象的临时存放点。它的生命周期很短主要服务于解决循环依赖的场景。一旦Bean完全初始化完毕它会被从earlySingletonObjects移动到singletonObjects然后在这里被清理掉。它就像一个餐厅的“备餐区”菜只进行了一半的加工比如肉切好了但还没下锅炒但因为下一道菜急需这个原料所以先把它拿出来应急。2.3 三级缓存singletonFactories– 生产半成品的工厂/** Cache of singleton factories: bean name to ObjectFactory. */ private final MapString, ObjectFactory? singletonFactories new HashMap(16);三级缓存是最特殊、也最容易被误解的一级。它存放的不是Bean对象本身而是一个ObjectFactory?对象工厂。这个工厂的作用是当需要获取某个Bean的早期引用时能够动态地创建或返回一个处理过的对象。为什么需要工厂而不是直接放对象这涉及到Spring AOP以及通过Async、Transactional等注解实现的代理。如果一个Bean需要被代理例如被AOP切面增强那么最终暴露给其他Bean使用的不应该是原始对象而应该是它的代理对象。这个代理对象何时创建是在Bean初始化后由BeanPostProcessor处理的。但在循环依赖的场景下其他Bean在属性注入阶段就需要引用这个Bean此时它的代理可能还没生成。ObjectFactory就是为了解决这个“时机”问题。它封装了一段逻辑当被调用时它可以判断当前情况决定是返回原始对象还是返回一个提前创建好的代理对象通过SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference方法。这给了Spring极大的灵活性。你可以把它理解为一张“菜品加工券”凭此券可以到后厨要求对半成品早期对象进行特定的加工如代理然后得到最终可用的形态。注意三级缓存singletonFactories在Bean的早期引用被获取一次后通常就会被移除。其对应的ObjectFactory是一次性的执行完就失效了。这是为了确保Bean引用的唯一性和一致性。3. 循环依赖的破局三级缓存协同作战全流程理论总是抽象的我们通过一个经典的Setter注入循环依赖场景来还原三级缓存是如何一步步配合打破僵局的。假设有AService和BService互相依赖。Service public class AService { Autowired private BService bService; // ... } Service public class BService { Autowired private AService aService; // ... }Spring容器启动开始创建AService这个Bean。这个过程发生在AbstractAutowireCapableBeanFactory.doCreateBean()方法中。3.1 第一步创建A实例并提前暴露工厂实例化Spring调用AService的构造方法创建出一个原始对象a。此时a里面的bService字段是null。暴露工厂关键操作在属性填充之前Spring会执行一个至关重要的操作——addSingletonFactory。// AbstractAutowireCapableBeanFactory.doCreateBean boolean earlySingletonExposure (mbd.isSingleton() this.allowCircularReferences isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { // 将BeanName和对应的ObjectFactory放入三级缓存 addSingletonFactory(beanName, () - getEarlyBeanReference(beanName, mbd, bean)); }此时AService对应的ObjectFactory被放入了三级缓存singletonFactories。这个工厂封装了获取AService早期引用的逻辑其中包含了处理AOP代理的可能性。注意此时一级和二级缓存都没有AService。3.2 第二步填充A的属性触发B的创建属性填充Spring开始为AService的实例a填充属性Autowired BService bService。获取B为了得到BService容器调用getBean(“bService”)。创建B实例和A一样Spring开始创建BService。先调用构造方法创建出原始对象b然后将BService的ObjectFactory也放入三级缓存。3.3 第三步填充B的属性向A求助B的属性填充Spring开始为BService的实例b填充属性Autowired AService aService。获取A循环点容器再次调用getBean(“aService”)来获取AService。三级缓存的第一次立功这次getBean不会从头创建A而是会触发缓存查找逻辑。在DefaultSingletonBeanRegistry.getSingleton(String, boolean)方法中查找顺序是一级缓存singletonObjects没有A还没初始化完。二级缓存earlySingletonObjects没有。三级缓存singletonFactories找到了之前存放的AService的ObjectFactory。执行工厂Spring调用这个ObjectFactory.getObject()。这个方法会执行getEarlyBeanReference如果AService需要被代理比如有AOP切面这里就会提前生成代理对象如果不需要则直接返回原始对象a。我们假设这里不需要代理返回了原始对象a。升级缓存从三级缓存获取到对象a后Spring会做两件事将对象a放入二级缓存earlySingletonObjects。将AService对应的ObjectFactory从三级缓存中移除。 现在AService的早期引用a存在于二级缓存中。这个a被成功注入到了BService的实例b中。3.4 第四步B完成初始化回归一级缓存B完成生命周期BService的属性aService已经注入完毕注入了A的早期引用a接着Spring完成BService的后续初始化执行PostConstruct等得到一个完全体b。B入驻一级缓存完全体b被放入一级缓存singletonObjects。同时BService相关的ObjectFactory从三级缓存移除早期引用从二级缓存移除如果之前有的话。3.5 第五步A完成初始化闭环A继续未竟之事此时AService的属性填充步骤之前在等getBean(“bService”)返回终于收到了返回值——刚刚创建好的完全体b。于是b被注入到a的bService字段中。A完成生命周期AService接着完成自己的初始化过程。A入驻一级缓存清理二级缓存完全体的a被放入一级缓存。同时Spring会发现AService在二级缓存中还有一个早期引用于是将其从二级缓存中移除。至此循环依赖完美解决。AService和BService的成品Bean都安静地待在一级缓存里可供随时使用。整个过程中三级缓存提供了获取早期引用的能力二级缓存作为临时存储避免了工厂的重复执行一级缓存则是最终的归宿。实操心得理解这个流程后你就能解释很多现象。比如为什么构造器注入无法解决循环依赖因为构造器注入发生在实例化阶段此时对象还没创建出来更无法提前暴露ObjectFactory到三级缓存死锁必然发生。Setter/字段注入之所以可以是因为注入发生在实例化之后、初始化之前那时已经有对象和工厂可以提前暴露了。4. 为什么必须是三级两级或一级不行吗这是一个经典的面试题也是理解Spring设计精妙之处的关键。我们分别来分析如果只有一级或两级缓存会怎样。4.1 假设只有一级缓存singletonObjects如果只有成品缓存那么流程根本无法进行。当创建A到一半需要B而创建B又需要A时由于A还没有成为“成品”未完成属性填充和初始化它不会被放入一级缓存。B在获取A时直接返回null或抛出异常循环依赖无解。所以必须有一个空间来存放“半成品”。4.2 假设只有两级缓存成品缓存半成品缓存这是我们思考的重点。很多初学者会想既然二级缓存earlySingletonObjects已经能存放早期对象了为什么还要三级缓存singletonFactories这个工厂直接把早期对象放进二级缓存不行吗理论上对于没有AOP的普通Bean是可行的。在A实例化后直接把原始对象a扔进二级缓存。B创建时需要A直接从二级缓存拿到a注入然后B完成初始化A再完成初始化。似乎也能跑通。但一旦引入AOP或任何需要创建代理的BeanPostProcessor问题就来了。核心矛盾在于代理对象创建的时机与循环依赖的需求时机存在冲突。正常的、无循环依赖的Bean创建流程实例化 - 属性填充 - 初始化 - (AOP)创建代理 - 放入一级缓存。代理是在初始化之后才创建的。循环依赖下的需求B在属性填充阶段就需要A的引用。如果此时A还在创建中它应该给B一个什么给原始对象但最终B注入的应该是A的代理对象否则AOP增强会失效例如Transactional注解的方法调用同类其他方法时如果注入的是原始对象事务会失效。给代理对象但A的初始化还没完成代理对象按理说还无法生成。三级缓存中的ObjectFactory正是为了解决这个“时机悖论”而设计的。它不是一个简单的对象存储而是一个延迟决策和处理的机制。当B通过getSingleton(“aService”)请求A时会调用三级缓存中的ObjectFactory.getObject()。这个方法内部会调用SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference()。Spring内置的AOP代理创建器AbstractAutoProxyCreator就实现了这个接口。如果A最终需要代理在getEarlyBeanReference()方法中AOP框架会判断是否已经为这个Bean创建过早期代理。如果是第一次被索取早期引用它会提前为A创建代理对象并返回。这个代理对象会被放入二级缓存后续所有需要A早期引用的地方虽然通常只有一个都从这个二级缓存获取保证了引用的一致性。如果A最终不需要代理getEarlyBeanReference()方法直接返回原始对象。所以三级缓存的核心价值在于将“早期引用”的生成逻辑封装成一个可延迟执行的工厂。它把“是否要创建代理”以及“如何创建代理”的决策推迟到真正有其他Bean需要注入它的那一刻从而完美适配了AOP代理的创建流程保证了在循环依赖场景下注入的引用与最终成品Bean无论是原始对象还是代理对象在类型和行为上的一致性。踩坑记录这就是为什么在我的开篇案例中给一个Service方法加上Async会引发循环依赖异常。Async也是通过BeanPostProcessor创建代理来实现的。在某些复杂的代理创建场景或代理处理器顺序问题下三级缓存的协调过程可能出现意外导致早期引用获取失败从而抛出BeanCurrentlyInCreationException。解决方法通常是调整Bean的依赖关系或者使用Lazy注解进行延迟注入打破即时的依赖索取。5. 三级缓存的边界与失效场景三级缓存机制虽然强大但它不是万能的。理解它的边界能帮助我们在设计时避免陷阱。5.1 非单例BeanPrototype三级缓存只针对单例SingletonBean。对于原型Prototype作用域的BeanSpring容器根本不会缓存它们每次getBean()都会创建一个新的实例。因此原型Bean之间的循环依赖Spring会直接抛出BeanCurrentlyInCreationException因为它无法也不应该去解决这种每次请求都产生新对象的依赖闭环。5.2 构造器注入Constructor Injection如前所述这是三级缓存机制无法解决的硬伤。因为构造器调用发生在实例化阶段的第一步此时Bean的实例尚未创建更谈不上将ObjectFactory加入三级缓存。当两个Bean都通过构造器相互依赖时Spring在启动时就会检测到并抛出异常。这是Spring官方明确声明不支持的情况。解决方法是改用Setter或字段注入或者重构设计消除循环依赖。5.3 某些特殊的BeanPostProcessor处理顺序Spring允许我们自定义BeanPostProcessor并且可以通过实现Ordered接口或使用Order注解来指定执行顺序。如果某个BeanPostProcessor在SmartInstantiationAwareBeanPostProcessor负责getEarlyBeanReference之前执行并且它试图去获取一个正在创建中的Bean的最终形态可能会遇到问题。因为此时可能连早期引用都还没生成。5.4allowCircularReferences配置在AbstractApplicationContext中有一个setAllowCircularReferences(boolean)方法默认是true。如果将其设置为falseSpring将完全禁止循环依赖三级缓存的循环依赖解决机制将被关闭。任何形式的循环依赖都会导致启动失败。这个配置在某些对代码质量要求极高、强制要求消除所有循环依赖的项目中可能会被使用。6. 从源码角度验证getSingleton方法逐行解析让我们聚焦到最核心的DefaultSingletonBeanRegistry.getSingleton(String, boolean)方法看看代码是如何实现上述逻辑的。这个方法清晰地展示了三级缓存的查询顺序和升级逻辑。// DefaultSingletonBeanRegistry.java protected Object getSingleton(String beanName, boolean allowEarlyReference) { // 1. 首先尝试从一级缓存成品缓存获取 Object singletonObject this.singletonObjects.get(beanName); // 如果没找到并且该Bean正在创建中说明可能存在循环依赖 if (singletonObject null isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { // 2. 尝试从二级缓存早期引用缓存获取 singletonObject this.earlySingletonObjects.get(beanName); if (singletonObject null allowEarlyReference) { // 3. 尝试从三级缓存工厂缓存获取工厂 ObjectFactory? singletonFactory this.singletonFactories.get(beanName); if (singletonFactory ! null) { // 4. 执行工厂获取早期对象 singletonObject singletonFactory.getObject(); // 5. 将获取到的对象放入二级缓存并从三级缓存移除工厂 this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return singletonObject; }这段代码是三级缓存协同工作的核心算法先查一级最快路径直接返回成品。再查二级如果Bean正在创建中说明它可能是个“半成品”去二级缓存找找看有没有提前放进去的早期引用。最后查三级如果二级也没有但允许早期引用allowEarlyReference通常为true就去三级缓存找工厂。工厂生产与缓存升级找到工厂后调用getObject()生产出早期对象可能是原始对象也可能是提前创建的代理。然后将这个对象升级到二级缓存同时删除三级缓存中的工厂。这个“升级”操作确保了同一个Bean的早期引用只会通过工厂创建一次后续的索取都直接走二级缓存保证了效率与一致性。7. 设计启示与最佳实践探究Spring三级缓存机制不仅能帮助我们解决实际问题更能获得一些深刻的设计启示。1. 空间换时间与延迟决策三级缓存本质上是“空间换时间”和“延迟决策”的经典结合。通过引入额外的存储结构二级、三级缓存避免了循环依赖导致的死锁。更重要的是通过ObjectFactory将代理对象的创建决策延迟到真正被需要的那一刻优雅地解决了代理时机问题。这在软件设计中是一个常用思路当面临不确定或成本较高的操作时先提供一个轻量的“承诺”或“工厂”等到必须执行时再兑现。2. 状态迁移的清晰界定从三级缓存工厂- 二级缓存半成品- 一级缓存成品Bean的状态迁移路径非常清晰。每一级缓存都代表了Bean生命周期的不同阶段。这种明确的状态划分使得代码逻辑如getSingleton方法可以有条不紊地处理各种边界情况。在我们的业务代码设计中明确对象的状态并为之设计相应的处理逻辑同样能减少Bug。3. 对Spring使用者的建议优先使用构造器注入虽然它不能解决循环依赖但它是一种更安全的依赖注入方式能明确声明Bean的必需依赖并使Bean在构造完成后就处于完全初始化的状态。很多现代Spring实践如Spring官方指南都推荐构造器注入作为首选。警惕循环依赖尽管Spring提供了三级缓存机制来救场但循环依赖本身是代码结构上的一个“坏味道”Code Smell它通常意味着类的职责边界不清晰耦合度过高。应当将其视为重构的提示考虑使用“引入第三方”、“事件驱动”、“方法参数传递”等方式来解耦。理解Lazy注解Lazy注解是解决某些复杂循环依赖场景的利器。它告诉Spring延迟初始化Bean或者在注入时先注入一个代理等到第一次真正调用时再初始化真实对象。这相当于在依赖链中插入了一个“缓冲”打破了即时的循环。但滥用Lazy可能会掩盖设计问题并带来运行时性能开销和调试复杂性。复杂AOP场景下的测试当你的服务层大量使用Transactional,Async,Cacheable等基于AOP的注解时在涉及循环依赖的Bean上进行集成测试尤为重要以确保代理被正确创建且行为符合预期。回过头看最初那个因Async引发的异常根本原因是在那个特定场景下代理创建链与三级缓存的交互出现了预期之外的情况。最终的解决方案并不是调整缓存而是通过代码重构将AService中一个独立的方法抽离到一个新的TaskService中由这个新Service来承载Async方法从而彻底消除了AService和BService之间的直接循环依赖。这再次印证了那句话框架提供的复杂机制是我们的安全网但清晰简洁的代码设计才是最好的保障。

相关新闻

深度解析中国建设银行肃宁支行网站如何助力本地企业与居民实现智慧金融服务升级

深度解析中国建设银行肃宁支行网站如何助力本地企业与居民实现智慧金融服务升级

在这个数字化的时代,我们每个人的生活节奏都在不断加快。早上匆匆忙忙挤公交,中午匆匆忙忙吃盒饭,晚上回到家只想瘫在沙发上刷手机。很多人觉得,银行这东西,不就是存取钱、买理财的地方吗?去趟柜台,排个号,填个单子,再等个半天。这种印象,其实早就过时了。现在的银行…

2026/10/12 9:26:49 阅读更多 →
如何在macOS上安装IINA播放器:免费开源视频播放器的完整指南

如何在macOS上安装IINA播放器:免费开源视频播放器的完整指南

如何在macOS上安装IINA播放器:免费开源视频播放器的完整指南 【免费下载链接】iina The modern video player for macOS. 项目地址: https://gitcode.com/gh_mirrors/iin/iina 你是否正在寻找一款既强大又美观的macOS视频播放器?IINA播放器正是你…

2026/10/4 11:54:37 阅读更多 →
如何打破Android截图限制?5分钟掌握Enable Screenshot终极解决方案

如何打破Android截图限制?5分钟掌握Enable Screenshot终极解决方案

如何打破Android截图限制?5分钟掌握Enable Screenshot终极解决方案 【免费下载链接】DisableFlagSecure 项目地址: https://gitcode.com/gh_mirrors/dis/DisableFlagSecure 你是否曾在银行应用中看到重要交易信息却无法截图保存?或者在支付软件中…

2026/10/10 23:01:06 阅读更多 →

最新新闻

GitHub热榜自动化抓取与解析技术指南

GitHub热榜自动化抓取与解析技术指南

我无法基于当前输入生成符合要求的博文。原因如下:输入中项目标题为“GitHub 热榜项目:日榜(2026-10-03)”,但该日期(2026年10月3日)是未来时间,明显不具备真实项目属性,…

2026/10/12 9:27:01 阅读更多 →
Strata双卡部署实战:释放中画幅AI影像引擎硬件潜力

Strata双卡部署实战:释放中画幅AI影像引擎硬件潜力

1. 这不是普通升级,是双卡用户的一次硬件价值重估Strata 这个名字最近在摄影和图像处理圈子里越来越响,尤其当它和 IQ3_S、IQ2_XS 这些中画幅数码后背型号一起出现时,几乎成了“高分辨率影像工作流最后一块拼图”的代名词。但很多人没意识到&…

2026/10/12 9:27:01 阅读更多 →
SAML 2.0单点登录原理与实战:SP、IdP、断言、证书全解析

SAML 2.0单点登录原理与实战:SP、IdP、断言、证书全解析

简介:一套围绕安全断言标记语言2.0规范实现的单点登录方案,面向需搭建统一身份认证体系的中高级开发者,亦覆盖VS2005、VS2008、VS2010等旧版开发环境,并包含部分Java辅助代码。资源完整呈现客户端发起认证请求、服务端信任校验、可…

2026/10/12 9:27:01 阅读更多 →
SAML 2.0 SSO单点登录实战:从协议原理到对接避坑指南

SAML 2.0 SSO单点登录实战:从协议原理到对接避坑指南

简介:基于SAML 2.0的SSO单点登录实现资料包,面向需要搭建统一身份认证系统的.NET开发人员、架构师,也适合对SAML协议交互流程感兴趣的Java开发者。资源聚焦客户端发送SAML请求、SSO响应验证客户端是否可信任、可信响应返回、加密SAML、客户端…

2026/10/12 9:26:00 阅读更多 →
车载颗粒物测量实战:OBS-ONE PM系统安装、测试与维护经验

车载颗粒物测量实战:OBS-ONE PM系统安装、测试与维护经验

第一次把颗粒物分析仪从实验室搬上卡车的时候,我心里想的是“把设备固定牢靠、管路接好,剩下的就是跑路、采数据”。等真正跑完一个完整的外场项目,我才发现OBS-ONE PM车载废气测量系统最难的部分从来不是仪器本身的精度,而是如何…

2026/10/12 9:26:00 阅读更多 →
FOD-A机场异物数据集实战:从数据转换到YOLO训练全指南

FOD-A机场异物数据集实战:从数据转换到YOLO训练全指南

简介:面向目标检测与计算机视觉研究者的FOD-A机场异物数据集,聚焦机场跑道常见异物碎片(FOD)检测,为缺乏公开标准数据的外物入侵检测任务提供训练与评测基础,也可支撑民航、机场场务等工业场景的智能巡检方…

2026/10/12 9:26:00 阅读更多 →

日新闻

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

在数码相机、高清显示屏与现代矢量图形技术高度发达的今天,画面可以做到绝对的锐利、平滑与无瑕。然而,当一张秋日手账插画或拍立得照片过于“平整无瑕”时,往往会散发出一种冰冷生硬的“数码塑料感(Digital Plasticity&#xff0…

2026/10/12 0:00:59 阅读更多 →
活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

在现代网页与移动端设计中,横排(Horizontal Layout)早已经成为了绝对的主流。然而,当我们翻开泛黄的线装古籍、宋版木刻诗集,或是欣赏一张茶道雅集的手写便签时,那种**自上而下纵向书写、自右向左逐列铺展&…

2026/10/12 0:00:59 阅读更多 →
周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

每到周日的晚上八点到十点,很多人心里都会悄悄亮起一盏警示灯。 在心理学上,这种现象有一个专门的称谓——“周日夜晚焦虑症(Sunday Scaries)”。明天又是周一,闹钟又要重新在七点响彻卧房;脑海里仿佛有一个…

2026/10/12 0:00:59 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/12 0:16:30 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/12 0:16:43 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 10:45:37 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:53 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 14:36:54 阅读更多 →