【问题标题】:Spring boot cross-reference issue randomly occursSpring boot 交叉引用问题随机出现
【发布时间】:2026-02-19 21:30:01
【问题描述】:

我在构建 Spring Boot 项目时遇到循环依赖(交叉引用)问题,并且依赖趋势如下:

  • Processor 类通过构造函数注入自动装配 Criteria 类;
  • Criteria 类通过构造函数注入自动装配 CacheManager;
  • CahceManager 类通过 setter 注入自动装配 RuleSet 类;
  • RuleSet 类通过构造函数注入再次自动装配处理器。
The dependencies of some of the beans in the application context form a cycle:
   app
┌─────┐
|  XXXProcessor defined in file ...
↑     ↓
|  XXXCriteria defined in file ...
↑     ↓
|  XXXCacheManager
↑     ↓
|  XXXRuleSet defined in file ...
└─────┘

虽然我可以努力从 RuleSet 类中删除 Processor 的依赖关系,但我想知道是否有一种方法可以保留当前引用但仍然消除此处介绍的交叉引用问题?我查看了这个论坛,有人建议 @Lazy 注释可能会有所帮助。我尝试将它应用于处理器类或 RuleSet 类(在类级别或方法级别),问题并没有消失。

另一个观察是,上面引用的错误并没有一直出现 - 有时程序运行得很好,是错误随机发生让我烦恼。为什么会这样?

【问题讨论】:

    标签: java spring spring-boot spring-annotations cross-reference


    【解决方案1】:

    解决它的一种方法是用Provider 替换一个实例,如下所示:

    public Processor(Provider<Criteria> criteria) {
        this.criteria = criteria;
    }
    

    那么在使用的时候需要先get()它。

    Criteria c = this.criteria.get();
    

    这意味着Processor 可以在Criteria 之前构造,因为注入的Provider 将在准备好后获得Criteria bean。

    这意味着你不能在构造函数中调用get(),否则你会得到一个运行时错误,因为这仍然意味着循环构造依赖。

    @Lazy 只是意味着 Spring 应该等待初始化一个 bean,直到它被实际请求,而不是在启动时急切地创建它(这是标准行为)。这对循环依赖和注入其他 bean 构造函数的 bean 的影响为零。它对于初始化非常慢并且必须几乎总是从 Provider 使用以实际延迟初始化的 bean 很有用。

    【讨论】:

      【解决方案2】:

      您可以在一处将构造函数注入替换为字段注入。它应该打破循环对象实例化的循环。

      很难说为什么这个问题会时不时发生。也许,有一些@Configuration 类根据配置值构建相同接口的不同实现。您应该提供更多详细信息来处理此问题。

      【讨论】: