java - Spring创建单例的多个实例?

标签 java spring singleton autowired applicationcontext

我有一张 Spring bean 的图表,它们相互 Autowiring 。非常简化的插图:

<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 都没有指定范围,这意味着它们是单例(使它们显式单例不会改变任何东西,我已经尝试过)。

问题是在单个应用上下文实例化后,BarBaz的实例包含不同的 Foo 的实例。怎么会这样?

我尝试为 Foo 创建 public no args 构造函数,并且调试已确认 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,然后将其 Autowiring 给任何想要它的人。

有趣的事实是,如果我使用带有 public static Foo getInstance 访问器的老式 private 构造函数,这工作得很好 - 在上下文设置期间不会引发异常。

FWIW,我正在使用带有 o.s.c.s.ClassPathXmlApplicationContext(String ...configLocations) 构造函数的 Spring 版本 3.0.5(也尝试使用 3.1.2,结果相同)。

我可以轻松地将我的代码转换为使用静态初始化程序,但我想了解为什么 Spring 会以这种方式运行。这是一个错误吗?

编辑:一些额外的调查表明

  • 应用上下文初始化后,所有后续对context.getBean(Foo.class) always的请求都返回相同的Foo实例.
  • @Autowired 替换为 setter(此 bean 大约有 20 次使用)仍会导致此对象的多个构造,但所有依赖项都注入(inject)了 相同的引用。

以上对我来说表明这是一个与 @Autowired 实现有关的 Spring 错误。如果我设法获得任何有用的信息,我将在 Spring 社区论坛上发帖并回帖。

最佳答案

如果您不小心使用 context:component-scan 注释,子上下文可以重新实例化相同的单例 bean(还有其他 Spring 上下文扫描注释,例如 MVC 和其他注释)。这是在 Web 应用程序中使用 Spring servlet 时的常见问题,请参阅 Why DispatcherServlet creates another application context?

确保您没有在子上下文中重新扫描您的组件,或者您只扫描特定的包/注释并从根上下文组件扫描中排除所述包/注释。

关于java - Spring创建单例的多个实例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11547240/

相关文章:

java - wss 协议(protocol)的 Apache 反向代理

java - 使用 JPA 存储枚举值

java - Android 静态引用强吗

java - Android 登录页面无法正常工作

java - 如何避免在 android Kitkat 4.4 中长按时默认选择?

java - IntelliJ 中的不适当 'unchecked assignment' 警告

java - 使用 Spring、Swing 和 SQLite 在 Java 中进行用户授权

c++ - 为了在测试中调用析构函数(用于测试),将基类静态转换为派生类有多可怕?

dependency-injection - 如何使用 NestJS 创建充当单例的服务

java - 如何在 Java 中的 Switch Case 中调用多个方法