29

我在使用 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。

4

3 回答 3

28

您可以使用@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 的接口,这将非常有效。

于 2012-07-05T16:48:04.120 回答
28

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

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

因为Spring会照顾它。它创建 bean 并根据需要注入它们

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

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

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 文件的加载顺序。在我的例子中,我使用<import resource="">. 即使使用相同的代码,加载顺序也可以根据环境进行更改,因此我建议设置顺序以消除潜在问题。

于 2014-11-30T06:33:22.287 回答
9

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

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

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

于 2012-07-05T16:54:06.027 回答