【发布时间】:2012-07-17 20:02:12
【问题描述】:
我有一个相互自动装配的 Spring bean 图。非常简化的插图:
<context:annotation-config/>
<bean class="Foo"/>
<bean class="Bar"/>
<bean class="Baz"/>
...
public class Foo {
@Autowired Bar bar;
@Autowired Baz baz;
}
public class Bar {
@Autowired Foo foo;
}
public class Baz {
@Autowired Foo foo;
}
所有这些 bean 都没有指定范围,这意味着它们是单例(使它们显式单例不会改变任何东西,我已经尝试过)。
问题在于,在单个应用程序上下文实例化之后,Bar 和Baz 的实例包含Foo 的不同 实例。怎么会这样?
我已尝试为Foo 创建公共无参数构造函数,并且调试已确认Foo 已多次创建。所有这些创建的堆栈跟踪都是here。
我还尝试为 Spring 启用调试日志记录,除此之外,得到以下结果:
DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'Foo'
DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'Foo'
DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'Foo'
我知道我的 bean 是相互交叉引用的,但我希望 Spring 框架能够尊重单例范围并初始化一个单例 bean,然后将其自动装配给任何想要它的人。
有趣的事实是,如果我将老式的 private 构造函数与 public static Foo getInstance 访问器一起使用,则效果很好 - 在上下文设置期间不会引发异常。
FWIW,我正在使用带有 o.s.c.s.ClassPathXmlApplicationContext(String ...configLocations) 构造函数的 Spring 版本 3.0.5(也尝试使用 3.1.2,结果相同)。
我可以轻松地将我的代码转换为使用静态初始化程序,但我想了解为什么 Spring 会以这种方式运行。这是一个错误吗?
编辑:一些额外的调查表明
- 应用上下文初始化后,所有后续对
context.getBean(Foo.class)的请求总是返回相同的Foo实例。 - 用 setter 替换
@Autowired(这个 bean 大约有 20 次使用)仍然会导致这个对象的多个构造,但所有依赖项都注入了相同的引用。
以上对我来说表明这是一个与 @Autowired 实现有关的 Spring 错误。如果我设法获得任何有用的信息,我将在 Spring 社区论坛上发帖并回帖。
【问题讨论】:
-
这可能很明显,但只有 1 个 JVM 在运行吗?循环依赖?
-
是的,这只是一个JVM。循环依赖 - 是的,但我相信我在我的帖子中解释了这一点。
-
我明白了,但是如果你有例如构造函数注入会发生什么? Spring 应该如何解决这个问题?
-
构造和连接给定对象不是单个原子,而是两个不同的操作。在我的示例中,容器可以先实例化所有 bean,然后再设置 @Autowired 依赖项。或者也许我没有明白你的意思 - 如果你有任何特殊情况,请分享。
-
我想您的示例过于简单,无法调查问题。 Stacktrace 显示涉及到一些
FactoryBean,以及FactoryBeans may cause problems with circular references。
标签: java spring singleton autowired applicationcontext