Spring AOP循环依赖深度解析:三级缓存原理与4种实战解法

咱们直接进入正题。做Spring开发的老哥们,特别是项目一复杂就疯狂堆@Service的团队,八成都在启动日志里见过类似“BeanCurrentlyInCreationException”或者“The dependencies of some of the beans in the application context form a cycle”这种报错。当这个报错再叠加AOP(比如事务、异步、自定义注解切面),排查难度直接翻倍,网上资料又一堆互相抄,看得人头大。今天这篇就把Spring中AOP循环依赖这件事从底层原理到实操解法完整梳理一遍,把坑提前踩平。

1. 先看真实场景:AOP和循环依赖撞车到底长什么样

1.1 一个典型的循环引用案例

假设我们有两个Service,业务上很常见:

@Service public class OrderService { private final UserService userService; public OrderService(UserService userService) { this.userService = userService; } @Transactional public void createOrder(String userId) { // 业务逻辑 userService.deductBalance(userId, 100); } } @Service public class UserService { private final OrderService orderService; public UserService(OrderService orderService) { this.orderService = orderService; } public void deductBalance(String userId, int amount) { // 扣余额逻辑 } }

如果你在Spring Boot 2.6之前的版本跑这段代码,并且两个Service都加了事务注解,大概率会在启动或者首次调用时出问题。但有意思的是,单纯下面的代码(不加AOP)在Spring Boot 2.6之前是能正常启动的,因为Spring容器内部其实支持单例bean的循环依赖处理,只有构造器注入这种“硬依赖”才会直接卡死。

真正让你崩溃的是把@Transactional一层加上去之后。因为事务要创建代理对象,而代理对象的创建时机和循环依赖的“早期引用”时机一旦对不上,容器就不知道该给你原始对象还是代理对象——这个点就是本文的核心矛盾。

1.2 循环依赖本质:容器创建bean时的“先有鸡还是先有蛋”

循环依赖可以简单理解为:A的创建需要B,B的创建又需要A。放在Spring里,创建bean的过程大致分三步:实例化(new出来)、填充属性(注入依赖)、初始化(执行init方法、AOP代理等)。

  • 实例化:调用构造器,生成了一个“半成品”对象,此时属性都是空的。
  • 填充属性:把依赖的其他bean注入进来。
  • 初始化:执行BeanPostProcessor的扩展逻辑,比如生成AOP代理。

问题来了:A实例化后要填充B,于是去创建B;B实例化后要填充A,但A还没走完填充和初始化,它只是个半成品。如果没有特殊机制,这里就死锁了。

Spring为了解决单例bean的setter注入循环依赖,设计了三级缓存。但注意,这个方案原本是给“普通bean”设计的,AOP代理的出现会把水搅浑。因为代理对象的生成通常发生在“初始化后置处理”阶段,而循环依赖要求A在“填充属性”阶段就把自己(哪怕是个半成品)提前暴露给别人,这就产生了冲突。

2. 解耦前先补基础:Spring三级缓存到底干了什么

2.1 三级缓存的结构和各自作用

很多人背过三级缓存,但真正懂应用场景的不多。直接看源码定义,Spring在DefaultSingletonBeanRegistry里维护了三个Map:

缓存等级数据结构存放内容作用
一级缓存singletonObjects完整的单例bean(属性填充完、初始化完、代理也生成完)最终对外提供使用的对象
二级缓存earlySingletonObjects早期暴露的bean引用(可能还是半成品,也可能已经是提前生成的代理对象)解决“提前暴露但还没走完完整初始化”的中间状态
三级缓存singletonFactories存放ObjectFactory函数式工厂接口真正打破循环依赖的关键,也承担了延迟生成代理对象的责任

需要特别强调的是,三级缓存里存的不是一个bean实例,而是一个ObjectFactory。这个工厂接口就一个方法getObject(),它在需要时才会去执行,返回当前bean的早期引用。如果是普通bean,工厂直接返回原始实例;如果bean需要AOP代理,工厂会在这一时刻提前触发代理生成逻辑。

2.2 AOP代理和三级缓存之间的微妙平衡

为什么非要用ObjectFactory而不是直接存早期对象?因为代理生成的时机太关键了。

正常情况下,一个bean经过完整生命周期后,会在初始化阶段由AbstractAutoProxyCreator(Spring AOP的核心处理器)创建代理对象,然后这个代理对象被放进一级缓存。一级缓存里的就是代理对象,你从容器里拿到的、注入到其他bean里的,都是这个代理对象。

但循环依赖的场景下,A在填充B的时候就已经要把自己暴露给B了,不可能等A走完初始化阶段。Spring的妥协方案是:在二级缓存里先放一个原始半成品或者“忽如其来”的代理对象,保证B能拿到一个引用。

具体流程拆解如下:

  1. A开始创建,createBean→ 实例化得到原始A对象 → 把ObjectFactory放入三级缓存。
  2. A填充属性时发现需要B,开始创建B实例。
  3. B实例化完成后,填充属性时发现需要A,此时从三级缓存里拿到A的ObjectFactory,调用getObject()。
  4. 关键点:此刻如果A需要AOP代理,getObject()内部会触发getEarlyBeanReference(),提前生成一个A的代理对象,放进二级缓存。
  5. B拿到A的引用(可能是代理对象),B后续初始化完成,进入一级缓存。
  6. A继续自己的初始化流程,初始化完成后,发现自己在二级缓存已经有对象了(提前生成的代理),于是直接把这个代理对象升级到一级缓存,不再重复创建代理。

所以,Spring AOP与循环依赖的兼容,本质上就是“在需要提前暴露的时候,就把代理也提前做好”。

3. 既然能兼容,为什么还会出问题

3.1 代理对象不一致的隐患

虽然上述流程听着顺畅,但也埋了雷:A在早期提前生成了代理对象,后续A自己的初始化阶段又该怎么处理?

Spring的AbstractAutoProxyCreator内部维护了一个earlyProxyReferences集合。getEarlyBeanReference()提前创建代理时,会把原始bean名记录到这个集合里。等A走完初始化,postProcessAfterInitialization()执行时,发现自己在早期已经生成过代理,就直接返回早期代理,不再重新代理。这样就保证了容器里最终只有一个代理对象,不会出现“两个代理”的情况。

这个机制在Spring AOP传统代理下是自洽的,但某些扩展点会翻车。比如@Async注解就不是走传统AOP的AbstractAutoProxyCreator,它走的是AsyncAnnotationBeanPostProcessor。这个处理器并没有实现getEarlyBeanReference()方法——也就是说,如果循环依赖发生在@Async代理下,Spring无法在早期阶段创建@Async代理,那B拿到的就只是原始A对象,而不是带异步增强的代理对象。

结果是:你调A.someAsyncMethod(),方法直接同步执行了,异步注解形同虚设。而且因为这个bug,Spring官方在某个版本后直接禁止了@Async与循环依赖共存,启动直接报错,防止你带病运行。

3.2 构造器注入循环依赖:真·死结

三级缓存只能救setter注入和字段注入(比如@Autowired字段注入)的循环依赖,对构造器注入完全无能为力。原因是:构造器注入发生在实例化阶段,也就是对象还没new出来之前你就要求注入依赖,此时连“半成品对象”都不存在,三级缓存里根本没有可用的引用。

@Service public class A { private final B b; public A(B b) { this.b = b; } } @Service public class B { private final A a; public B(A a) { this.a = a; } }

这种代码启动时必报BeanCurrentlyInCreationException,因为构造器的需求太早,Spring找不到任何缓存的早期引用。

所以,循环依赖问题最常见的“解锁密码”是setter注入或字段注入。构造器注入虽然官方推荐,但必须配合@Lazy才能解开循环。

3.3 Spring Boot 2.6之后的“一刀切”变化

Spring Boot 2.6版本做了一个大刀阔斧的改动:默认禁止循环依赖,spring.main.allow-circular-references属性默认设为false。这意味着以前靠setter注入勉强能跑的循环依赖代码,升到2.6以后直接启动失败。

我当时接手过这种项目,升级后几十个bean报循环依赖,排查起来非常酸爽。Spring Boot 这个决定本质上是想逼开发者直面循环依赖这个“坏味道”,因为从架构上讲,循环依赖往往意味着设计上耦合过重,应该重构而不是依赖容器兜底。

对我们的实操指导意义是:

  • 如果项目还在用Spring Boot 2.6以下,可以在配置里开启spring.main.allow-circular-references=true临时续命,但建议把重构循环依赖列入技术债。
  • 如果项目已经是2.6及以上,默认就不要指望循环依赖能跑通了,直接按“必须打破循环”的思路去设计。

4. 实践中真正有效的四个解法

4.1 解法一:重构拆分,消除循环依赖(首选)

这是从根上解决问题的方案。循环依赖多半是设计上职责不清导致的。A依赖B、B又依赖A,很多场景可以拆出一个C来承载公共逻辑或者事件解耦。

比如前面订单和用户余额的例子,可以引入事件机制或者独立服务:

@Service public class OrderService { private final UserQueryService userQueryService; public OrderService(UserQueryService userQueryService) { this.userQueryService = userQueryService; } @Transactional public void createOrder(String userId) { // 创建订单 } }

UserService就不再反向依赖OrderService,而是通过发布领域事件让订单侧响应。这种设计干净且符合单一职责,后续扩展也不容易再踩循环依赖。

4.2 解法二:利用@Lazy在构造器注入中打破循环

当重构代价太大,或者代码已经沉淀很久不想动,@Lazy是性价比最高的解法。它在注入时塞进去的是一个代理占位符,真正调用时才去容器获取目标bean。

@Service public class A { private final B b; public A(@Lazy B b) { this.b = b; } } @Service public class B { private final A a; public B(A a) { this.a = a; } }

注意@Lazy加在参数上,只对B这个代理生效。A的创建过程中不需要真正实例化B,而是拿到B的一个代理对象;B的创建过程中需要A时,A已经在三级缓存里有早期引用了,可以正常获取。这样两个构造器都能顺利完成。

@Lazy代理的关键限制是:B的方法通过代理调用时会触发拦截,如果B的bean尚未创建完成,代理会等容器完成创建后再调用。这在绝大多数业务场景下没问题,但如果你在A的构造方法里直接调用了B的方法,还是会出问题,因为构造阶段B可能还没就绪。

4.3 解法三:setter注入/字段注入配合@Autowired

在Spring Boot 2.6之前,把构造器注入改成setter注入,很多循环依赖就直接解了。因为setter注入发生在实例化之后,对象已经是半成品,能被B提前引用。

@Service public class A { private B b; @Autowired public void setB(B b) { this.b = b; } }

字段注入同理:

@Service public class A { @Autowired private B b; }

这种写法确实省事,但问题也不少:字段注入让依赖变得隐式化,单元测试时不好构造实例;而且没法加final,依赖可能被外部修改。所以就算用field注入解了循环依赖,也建议后续逐步改成构造器注入加@Lazy的组合。

4.4 解法四:针对AOP代理的专项调整

如果循环依赖已经发生且必须保留,同时AOP代理又是不可或缺的,有几个专项调整手段:

调整AOP代理暴露方式:Spring AOP默认是JDK动态代理。在某些情况下,换成CGLIB代理(spring.aop.proxy-target-class=true,其实Spring Boot默认就是CGLIB)可能让早期代理的兼容性更好。一般来说Spring Boot环境不需要手动设置,但如果你的项目是传统Spring XML配置,可以用<aop:aspectj-autoproxy proxy-target-class="true"/>强制启用CGLIB。

特殊处理@Async循环依赖:如果循环依赖的对象之间涉及@Async方法,不要指望三级缓存能解决异步代理的早期暴露问题。最快的处理方式是打破循环,其次是把@Async方法挪到单独的bean里,再注入进来。

自定义@Aspect切面的循环依赖:我们自己写@Aspect切面时一般不会碰循环依赖问题,因为切面本身是独立bean,切入的目标bean的循环依赖还是得靠Spring的三级缓存来兜底。但注意:切面注入目标bean时也会形成依赖关系,如果切面里注入了被切对象,同样可能出现循环。

举个例子:

@Aspect @Component public class LogAspect { private final OrderService orderService; public LogAspect(OrderService orderService) { this.orderService = orderService; } @Around("execution(* com.example.OrderService.*(..))") public Object log(ProceedingJoinPoint pjp) throws Throwable { return pjp.proceed(); } }

这里LogAspect依赖OrderService,而OrderService又被切面代理,实质上构成AOP切面与目标bean之间的循环依赖。遇到这种情况,优先解除切面对目标bean的依赖,比如通过ApplicationContext延迟获取,或者使用ObjectProvider注入。

5. 踩坑实录:AOP循环依赖问题排查与避坑清单

5.1 错误信息对照速查表

实际开发中,你可能遇到各种各样的启动报错。我整理了几个典型现象和对应原因:

报错/现象原因解决方向
BeanCurrentlyInCreationException构造器注入形成的循环依赖@Lazy打破,或重构
The dependencies of some beans form a cycleSpring Boot 2.6+禁用了循环依赖开启allow-circular-references,或拆循环
@Async方法执行不异步,方法同步执行@Async代理无法提前暴露拆循环,或把异步方法独立成bean
BeanPostProcessor循环依赖特有报错某些BeanPostProcessor本身需要被代理的对象给BeanPostProcessor加@Lazy,或拆散依赖
启动正常,但事务不生效AOP代理对象没被正确注入,注入了原始对象用CGLIB代理,或调整配置强制代理

5.2 日志分析:从启动顺序定位循环依赖链条

遇到循环依赖报错时,启动日志往往没有把整个引用链完整列出,需要自己分析。我常用的方法是:

  • 先看报错是从哪个bean名字开始,找到Currently in creation字样前后的bean链。
  • 在application.properties中开启DEBUG日志(logging.level.org.springframework.beans.factory=DEBUG),观察bean创建的顺序。
  • 如果项目基于Spring Boot,可以自定义一个BeanPostProcessor打印bean的创建顺序,或者在@Autowired的setter方法里加断点,实际调试时看堆栈调用。

例如日志里的线索:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'orderService': Requested bean is currently in creation: Is there an unresolvable circular reference?

这是典型的因为B创建时又回头找A,但A还没完成整个生命周期。此时直接看orderService和userService的依赖关系,就能快速锁定是哪一对对象在循环。

5.3 一个容易忽视的坑:ObjectProvider并不能解决AOP循环依赖

有些文章推荐使用ObjectProvider延迟获取依赖,有一定作用但不万能。

@Component public class A { private final ObjectProvider<B> bProvider; public A(ObjectProvider<B> bProvider) { this.bProvider = bProvider; } public void doSomething() { B b = bProvider.getIfAvailable(); // ... } }

ObjectProvider确实能在构造阶段延迟解析B,但当你真正调用getIfAvailable()时,容器仍然需要完成B的创建。如果B又依赖A,循环依赖依然成立。它更适合解决“可选依赖”或者“无法确定依赖实例化顺序”的复杂场景,而不是循环依赖的银弹。

5.4 排查工具和技巧

日常排查循环依赖,我推荐几种辅助手段:

  • 使用@DependsOn显式声明顺序:这个方法能解决部分启动顺序问题,但它控制的是bean的初始化顺序,不是创建顺序。循环依赖不会因为@DependsOn而消失,反而可能加剧启动失败。
  • 通过ApplicationContext.getBeanProvider(Class)在运行时延迟获取依赖,避免bean创建阶段的强依赖,进而解除启动期的循环。
  • 把单例改为@Scope("prototype"):原型bean不参与三级缓存,循环依赖会直接创建多份实例,但要注意每次注入都是新对象,业务语义可能改变,别乱用。

这些手段的核心思路是:不要让自己在bean创建阶段必须拿到一个尚未初始化的bean。

5.5 扩展知识:BeanPostProcessor自身触发循环依赖的诡异问题

有一种循环依赖非常隐蔽,与普通业务bean无关,发生在BeanPostProcessor和业务bean之间。

Spring在早期阶段就要提前实例化和注册所有BeanPostProcessor,如果我们自定义的BeanPostProcessor恰好注入了某个业务bean,而这个业务bean又依赖另一个业务bean,极端情况下可能触发非常诡异的循环依赖报错。

比如:

@Component public class MyBeanPostProcessor implements BeanPostProcessor { @Autowired private A a; // 这里注入业务Bean @Override public Object postProcessBeforeInitialization(Object bean, String beanName) { return bean; } }

这种设计极其不推荐,因为BeanPostProcessor是容器早期初始化的组件,它一上来就依赖业务bean,容易把创建顺序搅乱。如果业务bean又依赖其他组件,很容易形成环形依赖。正确做法是BeanPostProcessor中不要注入具体业务bean,需要使用时通过ApplicationContext延迟获取,而且只在业务方法里取,不要在处理器初始化阶段强取。

6. 最后再给一条走心的建议

循环依赖+AOP的问题,本质上是一个“设计缺陷被框架兼容”的麻烦事。三级缓存机制确实优秀,但它在兼容AOP时是小心翼翼打补丁,而不是一种值得信任的常规设计。我经手过几个老项目,很多循环依赖代码早期跑得挺欢,一升级依赖版本或者加了切面就冒出各种毛刺。处理这类问题我现在的习惯是:小循环直接用@Lazy,大循环坚定不移重构,构造器注入和@Async场景绝不硬凑。写完代码后顺手在启动配置里把spring.main.allow-circular-references关掉,让容器强制提醒你是否存在循环依赖,用这种“主动防御”的方式逼自己写出更干净的依赖结构。这样虽然前期改代码有点痛,但后期稳定性真不是靠缓存兜底的项目能比的。

相关新闻

OpenClaw:为大模型装上能干活的双手——AI Agent执行框架解析

OpenClaw:为大模型装上能干活的双手——AI Agent执行框架解析

1. 先从“脑”和“手”说起&#xff1a;OpenClaw解决的核心问题1.1 为什么大模型只能当“军师”&#xff0c;不能当“操盘手”这两年接触过的AI项目不少&#xff0c;一个最直观的感受是&#xff1a;大模型的“脑子”已经非常强了&#xff0c;强到能写文章、能解数学题、能跟你讨…

2026/10/20 8:56:30 阅读更多 →
论文解读与源码复现|LASB:薛定谔桥驱动的统一无监督异常检测(CVPR 2025)

论文解读与源码复现|LASB:薛定谔桥驱动的统一无监督异常检测(CVPR 2025)

论文解读与源码复现&#xff5c;LASB&#xff1a;薛定谔桥驱动的统一无监督异常检测&#xff08;CVPR 2025&#xff09; 论文首页题目与摘要截图 一、前言 工业质检与医学影像里的异常检测&#xff0c;主流是无监督"重构式"范式&#xff1a;只用正常样本训练&#…

2026/10/20 8:56:30 阅读更多 →
银行模拟程序:数据结构选型与离散事件仿真实战

银行模拟程序:数据结构选型与离散事件仿真实战

1. 项目概述&#xff1a;为什么一个银行模拟程序能成为数据结构教学的“试金石”“数据结构-银行模拟程序”这个标题乍看平平无奇&#xff0c;但在我带过的十几届学生项目实践中&#xff0c;它几乎稳居“最能暴露基础漏洞”的榜首。不是因为它有多复杂&#xff0c;恰恰相反——…

2026/10/20 8:55:28 阅读更多 →

最新新闻

AI课程矩阵实战路线:从提示词工程到API调用与批量部署

AI课程矩阵实战路线:从提示词工程到API调用与批量部署

AI 课程现在不难找&#xff0c;难的是判断一门课在你的成长路径里到底处于哪个位置。市面上大量课程要么只教提示词&#xff0c;要么直接堆 ComfyUI 节点&#xff0c;学完能复现案例&#xff0c;但换个场景就不会用了。“河南元力共生 AI 课程矩阵”这个提法&#xff0c;核心是…

2026/10/20 9:45:00 阅读更多 →
秋招十月下旬还没回音:剩下六周怎么排

秋招十月下旬还没回音:剩下六周怎么排

版权与内容来源声明 本文为原创整理。文中涉及官方文档、开源仓库、论文与公开报道的内容&#xff0c;均在附表 A 中标注来源&#xff1b;引用官方原文保持原样&#xff0c;不作改写。文中命令、版本号与界面截图以本文成文时的实测/核验结果为准&#xff0c;标注「待验证」的部…

2026/10/20 9:45:00 阅读更多 →
Matlab GUI实时均衡器:IIR滤波器零极点与音频信号流协同设计

Matlab GUI实时均衡器:IIR滤波器零极点与音频信号流协同设计

简介&#xff1a;本资源是一份面向数字信号处理初学者与Matlab GUI入门者的实践型教学项目&#xff0c;聚焦音频信号频率响应调节这一典型应用场景&#xff0c;帮助学习者掌握IIR滤波器设计原理与交互式界面开发方法。压缩包共3个文件&#xff08;2个.m主程序与辅助函数、1个.f…

2026/10/20 9:45:00 阅读更多 →
企业网盘选型实测:安全管控与协作效率深度对比

企业网盘选型实测:安全管控与协作效率深度对比

测评类文章最容易犯的毛病&#xff0c;就是把配置参数罗列一通&#xff0c;最后丢一句“按需选择”就完事。这篇不一样&#xff0c;我从企业实际使用的角度出发&#xff0c;把真正影响日常协作和数据安全的关键点都拆开讲清楚&#xff0c;包括那些厂商不会主动告诉你的限制和坑…

2026/10/20 9:45:00 阅读更多 →
AI日报系统设计与实现:从RSS聚合到智能摘要生成

AI日报系统设计与实现:从RSS聚合到智能摘要生成

我无法基于当前输入生成符合要求的博文。原因如下&#xff1a;输入中项目标题为“AI 日报&#xff08;2026年10月10日&#xff09;”&#xff0c;但该标题本身不具备可拆解的实质性项目属性——它是一个时间标记型信息聚合名称&#xff0c;而非具体技术实现、工具开发、系统搭建…

2026/10/20 9:45:00 阅读更多 →
FPGA+AD/DA协同设计:H题信号发生器与频谱分析的时序工程实践

FPGA+AD/DA协同设计:H题信号发生器与频谱分析的时序工程实践

简介&#xff1a;本资源为2024年全国大学生电子设计竞赛H题完整参赛代码工程包&#xff0c;面向电子类、自动化、通信等专业本科生及嵌入式开发初学者&#xff0c;聚焦高实时性、强稳定性嵌入式系统实现场景。压缩包含180个文件&#xff0c;主体为C语言源码&#xff08;c/h&…

2026/10/20 9:43:58 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

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

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

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

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

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

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/19 10:02:04 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 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/19 2:54:50 阅读更多 →
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/19 9:10:22 阅读更多 →
黑夜航拍船只数据集训练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/18 12:16:16 阅读更多 →