【问题标题】:What is the difference between a Spring singleton and a Java singeleton(design pattern)? [duplicate]Spring单例和Java单例(设计模式)有什么区别? [复制]
【发布时间】:2013-03-06 16:06:42
【问题描述】:

我正在学习 Spring 框架,目前正在阅读一本关于它的书。 在这本书中,它说 Spring 单例与 Java 单例不同? 这是什么意思,有什么区别? 谢谢

【问题讨论】:

  • 您已经很好地理解了与其他响应的区别,但这是我的两分钱,说明为什么人们可能不想要 Java 单例 - 可测试性。在写单元测试的时候,单例积累状态信息会不会造成问题?

标签: java spring dependency-injection singleton


【解决方案1】:

Java 单例由 Java 类加载器限定,Spring 单例由容器上下文限定。

这基本上意味着,在 Java 中,只有在加载它的类加载器的上下文中,您才能确定单例是真正的单例。其他类加载器应该能够创建它的另一个实例(假设类加载器不在同一个类加载器层次结构中),尽管您在代码中努力试图阻止它。

在 Spring 中,如果您可以在两个不同的上下文中加载单例类,那么我们可以再次打破单例概念。

因此,总而言之,如果 Java 不能在给定的类加载器中创建该类的多个实例,则 Java 将其视为单例,而 Spring 如果不能在给定的类加载器中创建多个类的实例,则将其视为单例。给定容器/上下文。

【讨论】:

  • 如果你在同一个 bean 定义/配置中用不同的 bean ID 声明同一个类,那么你将在“上下文中”拥有同一个类的两个不同实例。如果他打算在上下文/容器中使用单例,这可以解释为开发人员的配置错误。不能责怪 Spring 没有确保单例。如果我错了,请纠正我。
  • @user104309 :即使你两次声明同一个bean,它也只会被创建一次。 Spring 足够聪明来处理这个问题,当您尝试通过 ID 获取实例时,您可以进行“==”比较并自己测试它。
  • @Edwin Dalorzo:我看到您使用“容器/上下文”来解释弹簧单例,这可能会让某些人感到困惑。由于 spring bean 相对于容器是单例的,但可能不是上下文(即应用程序)。
【解决方案2】:

一个 Java 单例,根据设计模式,实例化被限制为一个,通常每个 JVM 类加载器的代码。 Wikipedia

Spring 单例 bean 可以是您编写的任何普通类,但将其范围声明为单例意味着 Spring 将仅创建一个实例并提供对所有引用已声明 bean 的 bean 的引用。您的应用程序中可能有许多该类的实例,但只会为 那个 bean 创建一个。您甚至可以将多个同一类的 bean 都声明为单例。每个 bean 都将创建该类的一个实例。 Spring 3.1 Doc

【讨论】:

  • +1,虽然你陷入了在解释 Spring 只有单例 beans 而不是单例 的同一段中写“A Spring 单例类”的陷阱类。 ;-)
  • @ruakh 很好,谢谢。
  • 实际上是通过类加载器,而不是通过 JVM。一个 JVM 可能有多个类加载器,每个类加载器都可能有一个单例类的实例(前提是它们不在同一个类加载器层次结构中)。
  • @EdwinDalorzo 谢谢,注意到了。
  • @EdwinDalorzo:我想我只是不认为这是关于单例类的事实,而是关于 JVM 中的类和类加载器的更普遍的事实。请注意,a.getClass() == b.getClass() 将是 false,如果它们来自不同的类加载器。 (此外,出于各种原因,即使在单个类加载器中,您也可以拥有一个具有多个实例的“单例类”。)