根据我的理解,单例基本上就是当你有一个私有成员代表你想拥有单个实例的对象时。然后在构造函数中初始化成员对象。
此对象的所有引用都是通过公共属性完成的,而public属性只引用已经实例化的私有成员。
现在在Web应用程序中,这是如何工作的?在tomcat关闭之前,单个实例是否只在容器中挂起(比如tomcat)?
答案 0 :(得分:6)
如果您的执行环境使用多个类加载器,那么每个类的实例就会得到一个单例。如果您的单例类被加载到不同的类加载器中,那么它实际上是两个不同的类,然后将有两个“单例”实例。
您可以在文档中找到Tomcat class loaders的一些信息。
答案 1 :(得分:5)
应该区分Singleton模式及其实现。大多数(如果不是所有)常见的Singleton实现都会遇到上面提到的类加载以及序列化,线程安全等问题。请参阅https://www.securecoding.cert.org/confluence/display/java/MSC07-J.+Prevent+multiple+instantiations+of+singleton+objects以获得详尽的概述。
然而,最广泛意义上的Singleton模式可以保证在特定上下文中唯一的任何服务。 Singleton的唯一性只能相对于给定的范围指定,如类加载器,JVM,容器或集群;唯一性的级别取决于实现,应根据应用程序的要求选择。
导致使用单例的两个非常常见的要求是依赖注入(c.q.使用工厂)和内存缓存。在这两种情况下都有良好的框架可以将Singleton方面隐藏在客户端之外,并在例如企业应用程序容器中提供足够的唯一性。对于依赖注入Spring,Guice或Pico会浮现在脑海中。对于缓存,我知道Ehcache是领先的解决方案,但肯定还有更多。 (有趣的琐事:'ehcache'这个名字是回文)
一般来说,单身人士的使用是“不受欢迎的”,并被视为反模式。另一方面,依赖注入和缓存等服务需要工作的唯一性。因此,如果我们宣称反单身,同时使用Spring或Ehcache等,我们就会愚弄自己。
在我看来,对单身人士的恐惧源于许多可能而且丰富的不良实施。即使Singleton实现本身是“安全的”,在整个应用程序中直接调用它(通过静态访问)会导致紧密耦合和可测试性差。
如果您的应用程序中有一个Singleton工厂,您可以进行的改进是重构其客户端,以便他们不需要在需要依赖项时调用工厂,而是提供私有字段和允许依赖项的公共setter被注射然后,您可以集中客户端的初始化,可能在同一个工厂中,并使客户端代码保持干净,松散耦合和可测试(您现在可以注入模拟依赖项)。这也可能是引入像Spring这样的依赖注入框架的第一步。
我希望在这个漫长而漫无边际的帖子中的某个地方,我帮助回答了你的问题! ( - ;
答案 2 :(得分:0)
现在在Web应用程序中,这是如何工作的?在tomcat关闭之前,单个实例是否只在容器中挂起(比如tomcat)?
@Greg的回答解释说,如果TomCat中的每个webapp容器都有自己的类加载器,那么单例类可能会有不同的实例(从JVM的角度来看实际上是不同的类)。
无论哪种方式,单例的(GC)生命周期都是各个类加载器的生命周期。但实际上,对类加载器的引用很容易泄漏,导致单例生存直到JVM退出。
这是传统单例在Web应用程序中存在问题的原因之一。最好使用“容器范围”实例;例如由Spring和其他IoC框架支持。
答案 3 :(得分:0)
是的,有一个单例模式,按照你的描述工作。这是有问题的,并且上面提到了Stephen C提到的警告。如果你需要单个实例数据,你最好的选择就是让它由spring容器(或其他支持它的容器)构建,它将处理实例化(这比你想象的要多得多)。
如果您必须自己动手,请仔细阅读上的 以及其附带的问题,以了解单例实例化可能出现的问题。如果您的实例化非常重要,实际上很容易在实例化中获得多个实例或竞争条件。我自己做了。在生产中(但很久以前;))