24

我在工作中的一个项目有一个循环引用使用Spring,对此我无法修复,并失败,出现以下错误启动:春圆形参考示例

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

我试着在示例项目的较小级别重新创建相同的问题(没有我的工作项目的所有细节)。然而,我一直无法想出一个合理的情况,即春天失败并出现错误。 这是我有:

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(); 
    } 
} 

我有一个类似的场景在我的项目,该项目失败,我期待春天在我的样本项目,抱怨也是如此。但它工作正常!有人能给我一个简单的例子,说明如何用循环引用错误来破解弹簧吗?

编辑:我使用javax.inject.Provider固定的问题。 2个项目中唯一的另一个区别是使用的注释是javax.inject.Inject和javax.annotation.ManagedBean来代替@Autowired和@Component。

回答

23

这是一个古老的线程,所以我想你几乎忘了这个问题,但我想让你知道这个谜。我遇到了同样的问题,而且我的魔法并没有消失,所以我必须解决问题。我会一步一步解决你的问题。

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

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

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

  • 作为@sperumal说,如果你使用构造器注入
  • 根据日志弹簧可产生圆形异常,你使用Spring Security在你的项目
  • 在春季安全配置,他们确实使用构造函数注射
  • 你豆类中注入了authenticationManager有循环引用

3,那为什么有恩ception走神秘?

可能发生或可能不发生的异常取决于bean的创建顺序。我猜你做几个*context.xml文件左右,并在web.xml

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

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

4.如何解决问题?

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

26

你可以使用@Lazy,表明bean被延后创建,打破自动装配的渴望循环。

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

从Spring的吉拉一个问题:可在结合使用@Configuration ,表明该配置类中的所有豆类应 延迟初始化

@Lazy注解。当然,@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(); 
    } 
} 

如果您实现您的豆这会工作得很好的接口。

+1

只是为了增加这一点,我们遇到了类似的问题(注入SpringTemplateEngine)。 “setter注入”解决方案没有帮助,但“@ Lazy”注解做到了。这感觉就像一个弹伤创伤的创可贴,但现在我会取胜并走开。谢谢Spaeth先生。 – demaniak 2016-02-08 15:33:59

9

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

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

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

+2

我想你误解了那里写的东西:如果你主要使用构造函数注入,**可能会创建一个无法解析的循环依赖方案。 – 2012-07-05 16:58:35

+1

构造函数注入优于setter注入 - 在构造函数调用完成之前,您的bean不存在,而使用setter注入时,您可能省略了一些必要的参数,并且bean在未正确配置的状态下存在一段时间 – 2012-07-05 18:21:28