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

根据我的理解,单例基本上是当你有一个私有成员代表你想拥有单个实例的对象时。 然后在构造函数中初始化成员对象。

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

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

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

您可以在文档中找到有关Tomcat类加载器的一些信息。

应该区分Singleton模式及其实现。 大多数(如果不是全部)常见的Singleton实现都会遇到上面提到的类加载以及序列化,线程安全等问题。请参阅https://www.securecoding.cert.org/confluence/display/java/MSC07-J.+Prevent+multiple +实例化+ +单例+对象,以获得非常全面的概述。

但是,最广泛意义上的Singleton模式可以保证在特定上下文中唯一的任何服务。 Singleton的唯一性只能相对于给定的范围指定,如类加载器,JVM,容器或集群; 唯一性的级别取决于实现,应根据应用程序的要求进行选择。

导致使用单例的两个非常常见的要求是dependency injection(使用工厂的cq)和内存缓存。 在这两种情况下都有良好的框架可以将Singleton方面隐藏在客户端之外,并在例如企业应用程序容器中提供足够的唯一性。 对于dependency injectionSpring,Guice或Pico会浮现在脑海中。 对于缓存,我知道Ehcache是​​领先的解决方案,但肯定还有更多。 (有趣的琐事:’ehcache’这个名字是一个回文)

一般来说,单身人士的使用是“不受欢迎的”,并被视为一种反模式。 另一方面,dependency injection和缓存等服务需要工作的唯一性。 因此,如果我们宣称反单身,同时使用Spring或Ehcache等,我们就会愚弄自己。

在我看来,对单身人士的恐惧源于许多可能而且丰富的不良实施。 即使Singleton实现本身是“安全的”,在整个应用程序中直接调用它(通过静态访问)会导致紧密耦合和可测试性差。

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

我希望在这个漫长而漫无边际的post中的某个地方帮助回答你的问题! ( – ;

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

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

无论哪种方式,单例的(GC)生命周期将是各个类加载器的生命周期。 但实际上,引用类加载器很容易泄漏,导致单例生存直到JVM退出。

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

是的,有一个单例模式,按照你的描述工作。 这是有问题的,并附有上述Stephen C提到的警告。 如果你需要单实例数据,你最好的选择是让它由spring容器(或其他支持它的容器)构建,它将处理实例化(这比你想象的要多得多)。

如果你必须自己动手,请仔细阅读双重检查的锁定习语以及随之而来的问题,以了解单例实例化可能出现的问题。 如果您的实例化非常重要,实际上很容易在实例化中获得多个实例或竞争条件。 我自己做了。 在生产中(但很久以前;))