【问题标题】:Spring circular reference exampleSpring循环引用示例
【发布时间】:2012-07-06 02:54:17
【问题描述】:

我有一个循环引用在我的一个项目中使用 spring,我无法修复它,并且在启动时失败并出现以下错误:

'org.springframework.security.authenticationManager': Requested bean is currently in creation: Is there an unresolvable circular reference?

我尝试在示例项目中以较小的级别重新创建相同的问题(没有我工作项目的所有细节)。然而,我一直无法想出一个合理的场景,即 spring 因错误而失败。 这是我所拥有的:

public class ClassA {
    @Autowired
    ClassB classB;
}

public class ClassB {
    @Autowired
    ClassC classC;
}

@Component
public class ClassC {
    @Autowired
    ClassA classA;
}

@Configuration
public class Config {
    @Bean
    public ClassA classA() {
        return new ClassA();
    }

    @Bean
    public ClassB classB() {
        return new ClassB();
    }
}

我的项目中有类似的场景,但失败了,我期待 spring 也会在我的示例项目中抱怨。但它工作正常!谁能给我一个简单的例子,说明如何用循环引用错误来打破弹簧?

编辑:我使用 javax.inject.Provider 解决了这个问题。这两个项目中唯一的其他区别是使用的注解是 javax.inject.Inject 和 javax.annotation.ManagedBean 代替了@Autowired 和@Component。

【问题讨论】:

    标签: java spring dependency-injection autowired circular-reference


    【解决方案1】:

    这是一个旧线程,所以我猜你几乎忘记了这个问题,但我想让你知道这个谜团。我遇到了同样的问题,我的并没有神奇地消失,所以我必须解决这个问题。我会一步一步解决你的问题。

    1.为什么不能重现循环引用异常?

    因为Spring takes care of it. It creates beans and injects them as required

    2。那你的项目为什么会产生异常呢?

    • 正如@sperumal 所说,如果使用构造函数注入,Spring 可能会产生循环异常
    • 根据日志,你在项目中使用了Spring Security
    • 在 Spring Security 配置中,它们确实使用构造函数注入
    • 您注入 authenticationManager 的 bean 具有循环引用

    3。那为什么异常神秘地消失了呢?

    异常可能发生也可能不发生取决于 bean 的创建顺序。我猜你制作了几个 *context.xml 文件左右,并在 web.xml 中使用如下配置加载它们

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:*-context.xml</param-value>
    </context-param>
    

    xml 文件将由XmlWebApplicationContext 类加载,文件的加载顺序不保证。它只是从文件系统加载文件。问题就在这里。如果类首先加载应用程序上下文文件没有问题,因为您的bean在用于Spring Security的构造注入时已经创建。但是,如果它首先加载 Spring Security 上下文文件,就会出现循环引用问题,因为 Spring 会在构造函数注入之前尝试使用您的 bean。

    4.如何解决问题?

    强制 xml 文件的加载顺序。就我而言,我使用&lt;import resource=""&gt; 在应用程序上下文文件的末尾加载了安全上下文xml 文件。即使使用相同的代码,加载顺序也可以根据环境更改,因此我建议设置顺序以消除潜在问题。

    【讨论】:

      【解决方案2】:

      根据 Spring 文档,可以使用 构造函数注入 获得循环依赖问题或BeanCurrentlyInCreationException

      解决此问题的解决方案是使用 setter 而不是构造函数注入。

      参考http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/beans.html

      【讨论】:

      • 我想你误解了那里写的内容:如果你主要使用构造函数注入,有可能创建一个无法解决的循环依赖场景。
      • 构造函数注入优于 setter 注入 - 在构造函数调用完成之前,您的 bean 不存在,而使用 setter 注入,您可能会省略一些必要的参数,并且 bean 在未正确配置状态下存在一段时间跨度>
      【解决方案3】:

      您可以使用@Lazy 表示 bean 是延迟创建的,从而打破了自动装配的急切循环。

      这个想法是循环中的某些 bean 可以被实例化为代理,并且在真正需要它的那一刻它将被初始化。这意味着,除了作为代理的 bean 之外,所有 bean 都被初始化。第一次使用它会触发配置,因为其他 bean 已经配置,所以不会有问题。

      来自 Spring-Jira 中的一个问题:

      @Lazy 注解可以与@Configuration 结合使用 表示该配置类中的所有 bean 都应该是 懒惰地初始化。当然@Lazy也可以配合使用 使用单独的 @Bean 方法来指示延迟初始化 一个一个的基础。 https://jira.springsource.org/browse/SJC-263

      这意味着将您的 bean 注释为 @Lazy 就足够了。或者,如果您更喜欢将配置类注释为 @Lazy,如下所示:

      @Configuration
      @Lazy
      public class Config {
          @Bean
          public ClassA classA() {
              return new ClassA();
          }
      
          @Bean
          public ClassB classB() {
              return new ClassB();
          }
      }
      

      如果您实现 bean 的接口,这将非常有效。

      【讨论】:

      • 只是补充一点,我们遇到了类似的问题(注入 SpringTemplateEngine)。 “setter injection”解决方案没有帮助,但 @Lazy 注释起到了作用。感觉就像是子弹伤口上的创可贴,但现在我会赢得胜利并走开。谢谢斯派思先生。
      猜你喜欢
      • 1970-01-01
      • 2010-12-02
      • 2018-03-22
      • 1970-01-01
      • 1970-01-01
      • 2015-05-18
      • 2023-03-24
      • 2016-01-26
      • 1970-01-01
      相关资源
      最近更新 更多