Java 在web应用程序中如何处理单例?

Java 在web应用程序中如何处理单例?,java,singleton,Java,Singleton,据我所知,单例基本上是指当您拥有一个私有成员,该成员表示您希望拥有单个实例的对象时。然后在构造函数中初始化成员对象 此对象的所有引用都通过公共属性完成,而公共属性仅引用已实例化的私有成员 现在在web应用程序中,这是如何工作的?在tomcat关闭之前,容器中是否只有一个实例(比如tomcat)?如果您的执行环境使用多个类加载器,那么您的类的每个实例都有一个单例。如果您的单例类被加载到不同的类加载器中,那么它实际上是两个不同的类,然后将有两个“单例”实例 您可以在文档中找到有关的一些信息 现在在w

据我所知,单例基本上是指当您拥有一个私有成员,该成员表示您希望拥有单个实例的对象时。然后在构造函数中初始化成员对象

此对象的所有引用都通过公共属性完成,而公共属性仅引用已实例化的私有成员


现在在web应用程序中,这是如何工作的?在tomcat关闭之前,容器中是否只有一个实例(比如tomcat)?

如果您的执行环境使用多个类加载器,那么您的类的每个实例都有一个单例。如果您的单例类被加载到不同的类加载器中,那么它实际上是两个不同的类,然后将有两个“单例”实例

您可以在文档中找到有关的一些信息

现在在web应用程序中,这是如何工作的?在tomcat关闭之前,容器(比如tomcat)中是否只有一个实例

@Greg的回答解释说,如果TomCat中的每个webapp容器都有自己的类加载器,那么可能会有不同的singleton类实例(从JVM的角度来看,实际上是不同的类)

无论哪种方式,单例的(GC)生存期都将是相应类加载器的生存期。但在实践中,对类加载器的引用很容易泄漏,导致在JVM退出之前单例一直存在


这是传统的单例在web应用程序中存在问题的原因之一。最好使用“容器范围”实例;e、 g.由Spring和其他IoC框架支持。

是的,有一个单例模式,正如您所描述的。这是一个有问题的问题,正如上面Stephen C所提到的,它附带了一些警告。如果您需要单实例数据,那么最好的选择是让它由spring容器(或支持此功能的其他容器)构建,它将处理实例化(这比您想象的要麻烦得多)


如果您必须自己动手,请仔细阅读双重检查锁定习惯用法及其附带的问题,以了解单例实例化可能带来的问题。如果您的实例化非常简单,那么在实例化中很容易获得多个实例或竞争条件。我自己做的。在生产中(但那是很久以前的事了)

应该区分单例模式及其实现。大多数(如果不是所有的话)常见的单例实现都会遇到上面提到的类加载以及序列化、线程安全等问题。请参阅,以获得非常全面的概述

然而,最广义的单例模式可以是保证在特定上下文中唯一的任何服务。单例的唯一性只能相对于给定的作用域(如类加载器、JVM、容器或集群)来指定;唯一性级别取决于实现,应根据应用程序的需求选择实现

导致使用单例的两个非常常见的需求是依赖注入(c.q.使用工厂)和内存缓存。在这两种情况下,都有很好的框架可以对客户机隐藏单例方面,并在例如企业应用程序容器中提供足够级别的唯一性。对于依赖注入Spring,我们会想到Guice或Pico。对于缓存,我知道Ehcache是领先的解决方案,但肯定还有更多。(有趣的琐事:“ehcache”这个名字是回文)

一般来说,单身人士的使用是“不受欢迎的”,并被视为一种反模式。另一方面,依赖注入和缓存等服务需要唯一性才能工作。因此,如果我们宣称自己是反单例的,同时使用Spring或Ehcache之类的工具,那我们就有点自欺欺人了

在我看来,对单例的恐惧源于可能的、大量的、糟糕的实现。即使单例实现本身是“安全的”,在整个应用程序中直接调用它(通过静态访问)也会导致紧密耦合和较差的可测试性

如果您的应用程序中有一个单例工厂,您可以做的一个改进是重构它的客户机,这样他们就不会在需要依赖项时调用工厂,而是提供一个私有字段和一个公共setter,允许注入依赖项。然后,您可以将客户机的初始化集中在同一个工厂中,并保持客户机代码干净、松散耦合和可测试(现在可以注入模拟依赖项)。这也可能是引入依赖注入框架(如Spring)的第一步

我希望在这篇相当长且杂乱无章的文章中,我能帮助回答你的问题!(-)