Spring循环参考示例

时间:2012-07-05 16:40:12

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

我在使用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解决了这个问题。两个项目中唯一的另一个区别是使用的注释是javax.inject.Inject和javax.annotation.ManagedBean代替@Autowired和@Component。

4 个答案:

答案 0 :(得分:26)

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

答案 1 :(得分:26)

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

<强> 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的构造注入时已经创建了bean。但是,如果它首先加载Spring Security上下文文件,则会出现循环引用问题,因为Spring会在创建之前尝试在构造函数注入中使用bean。

<强> 4。如何解决问题?

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

答案 2 :(得分:9)

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

解决问题的方法是使用setter而不是Constructor injection。

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

答案 3 :(得分:2)

关于此事的一些解读:

http://blog.jdevelop.eu/?p=382

这种循环依赖关系并不酷,应尽可能避免