弹簧圆形参考示例

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


答案 1

您可以使用来指示Bean是懒惰地创建的,从而打破了自动布线的急切循环。@Lazy

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

摘自《Spring-Jira》的一期:

@Lazy可与@Configuration结合使用的注释,以指示应延迟初始化该配置类中的所有 Bean。当然,@Lazy也可以与单个@Bean方法结合使用,以逐个指示延迟初始化。https://jira.springsource.org/browse/SJC-263

这意味着注释你的豆子就足够了。或者,如果您愿意,只需按如下方式对配置类进行注释:@Lazy@Lazy

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

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

如果你实现了你的bean的接口,这将很好地工作。


答案 2

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

1. 为什么无法重现循环引用异常?

因为春天照顾它。它创建豆子并根据需要注入它们

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

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

3.那么,为什么例外神秘地消失了呢?

异常可能发生,也可能不发生取决于 bean 的创建顺序。我猜你制作了几个文件左右,然后用像下面这样的配置加载它们.xml*context.xml

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

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

4. 如何解决问题?

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


推荐