java Web 应用程序中如何处理单例?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2391191/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How are singletons handled in a web application?
提问by Blankman
From what I understand, a singleton is basically when you have a private member that represents the object you want to have a single instance for. Then in the constructor you initialize the member object.
据我了解,单例基本上是当您有一个私有成员代表您想要为其拥有单个实例的对象时。然后在构造函数中初始化成员对象。
All references for this object are done via a public property, and the public property just references the private member that has already been instantiated.
这个对象的所有引用都是通过公共属性完成的,公共属性只引用已经实例化的私有成员。
Now in a web application, how does this work? Does a single instance just hang around in the container (say tomcat) until tomcat is shutdown?
现在在 Web 应用程序中,这是如何工作的?单个实例是否只是挂在容器中(比如 tomcat)直到 tomcat 关闭?
回答by Greg Hewgill
If your execution environment uses multiple class loaders, then you get one singleton per instance of your class. If your singleton class is loaded into different class loaders, then it's actually two distinct classes and then there will be two "singleton" instances.
如果您的执行环境使用多个类加载器,那么您的 class 的每个实例都会得到一个单例。如果你的单例类被加载到不同的类加载器中,那么它实际上是两个不同的类,然后会有两个“单例”实例。
You can find some info on the Tomcat class loadersin the documentation.
您可以在文档中找到有关Tomcat 类加载器的一些信息。
回答by Adriaan Koster
A distinction should be made between the Singleton pattern, and its implementation. Most if not all common Singleton implementations suffer from the mentioned problems with classloading as well as serialization, thread safety etc. See https://www.securecoding.cert.org/confluence/display/java/MSC07-J.+Prevent+multiple+instantiations+of+singleton+objectsfor a quite thorough overview.
应该区分单例模式及其实现。大多数(如果不是全部)常见的单例实现都存在上述提到的类加载以及序列化、线程安全等问题。请参阅https://www.securecoding.cert.org/confluence/display/java/MSC07-J.+Prevent+multiple +instantiations+of+singleton+objects以获得非常全面的概述。
However, the Singleton pattern in its broadest sense can be any service guaranteed to be unique within a certain context. The uniqueness of a Singleton can only be specified relative to a given scope like a classloader, JVM, container or cluster; the level of uniqueness depends on the implementation, which should be chosen based on the application's requirements.
但是,从最广泛的意义上讲,单例模式可以是任何保证在特定上下文中唯一的服务。Singleton 的唯一性只能相对于给定的范围指定,如类加载器、JVM、容器或集群;唯一性的级别取决于实现,应该根据应用程序的要求选择实现。
Two very common requirements leading to the use of Singletons are dependency injection (c.q. using a factory) and in-memory caching. In both cases there are good frameworks that hide the Singleton aspect from the client and offer a sufficient level of uniqueness within for instance an enterprise application container. For dependency injection Spring, Guice or Pico come to mind. For caching I know Ehcache as leading solution, but there are certainly more out there. (fun trivia: The name 'ehcache' is a palindrome)
导致使用单例的两个非常常见的要求是依赖注入(cq 使用工厂)和内存缓存。在这两种情况下,都有很好的框架可以对客户端隐藏 Singleton 方面,并在例如企业应用程序容器中提供足够级别的唯一性。对于依赖注入 Spring,Guice 或 Pico 浮现在脑海。对于缓存,我知道 Ehcache 是领先的解决方案,但肯定还有更多解决方案。(有趣的琐事:“ehcache”这个名字是一个回文)
In general, use of Singletons is 'frowned upon', and seen as an anti-pattern. On the other hand, services like dependency injection and caching require uniqueness to work. So we are fooling ourselves a bit if we proclaim to be anti-Singleton and at the same time use Spring or Ehcache or the like.
一般来说,单例的使用是“不赞成的”,并被视为一种反模式。另一方面,依赖注入和缓存等服务需要唯一性才能工作。因此,如果我们宣称自己是反单例并同时使用 Spring 或 Ehcache 之类的,那我们就有点自欺欺人了。
The fear of Singletons in my opinion stems from the many poor implementations that are possible, and abundant. And even if the Singleton implementation itself is 'safe', calling it directly (via static access) throughout the application leads to tight coupling and poor testability.
在我看来,对单身人士的恐惧源于许多可能的糟糕实现,而且数量众多。即使单例实现本身是“安全的”,在整个应用程序中直接(通过静态访问)调用它也会导致紧密耦合和较差的可测试性。
An improvement you can make if you have a Singleton factory in your application, is to refactor its clients so that they don't call the factory whenever they need a dependency, but provide a private field and a public setter allowing the dependency to be injected. You can then centralize the initialization of the clients, maybe in the same factory, and leave the client code clean, loosely coupled and testable (you can inject mock dependencies now). This could also be a first step towards introducing a dependency injection framework like Spring.
如果您的应用程序中有单例工厂,您可以进行的改进是重构其客户端,以便它们在需要依赖项时不会调用工厂,而是提供私有字段和公共设置器,允许注入依赖项. 然后,您可以集中初始化客户端,可能在同一个工厂中,并使客户端代码保持干净、松散耦合和可测试(您现在可以注入模拟依赖项)。这也可能是引入像 Spring 这样的依赖注入框架的第一步。
I hope somewhere in this rather long and rambling post I helped answer your question! (-;
我希望在这篇相当长且杂乱无章的帖子中的某个地方我帮助回答了您的问题!(-;
回答by Stephen C
Now in a web application, how does this work? Does a single instance just hang around in the container (say tomcat) until tomcat is shutdown?
现在在 Web 应用程序中,这是如何工作的?单个实例是否只是挂在容器中(比如 tomcat)直到 tomcat 关闭?
@Greg's answer explains that there may be a different instances of the singleton class (actually different classes from the JVM's perspective) if each webapp container in TomCat has its own classloader.
@Greg 的回答解释说,如果 TomCat 中的每个 webapp 容器都有自己的类加载器,那么可能会有不同的单例类实例(从 JVM 的角度来看实际上是不同的类)。
Either way, the (GC) lifetime of a singleton will be the lifetime of the respective classloaders. In practice though, it is easy for references to a classloader to leak, resulting in the singleton living until the JVM exits.
无论哪种方式,单例的 (GC) 生命周期都将是相应类加载器的生命周期。但在实践中,对类加载器的引用很容易泄漏,导致单例一直存在,直到 JVM 退出。
This is one of the reasons that conventional singletons are problematic in web applications. It is better to use "container scoped" instances; e.g. as supported by Spring and other IoC frameworks.
这是传统单例在 Web 应用程序中存在问题的原因之一。最好使用“容器范围”实例;例如,由 Spring 和其他 IoC 框架支持。
回答by Steve B.
Yes, there's a singleton pattern, which works as you describe. It's problematic and comes with caveats as mentioned by Stephen C above. If you need single instance data your best option is to have it built by a spring container (or other containers that support this), which will handle the instantiation (which is much more problematic than you might think).
是的,有一个单例模式,它按照你的描述工作。这是有问题的,并带有上面斯蒂芬 C 提到的警告。如果您需要单实例数据,最好的选择是由 spring 容器(或支持此功能的其他容器)构建它,它将处理实例化(这比您想象的要麻烦得多)。
If you must roll your own, read up thoroughlyon the double-checked locking idiom and the issues that come with it to understand the issues that can come up with singleton instantiation. If your instantiation is non-trivial it's actually very easy to get multiple instances or race conditions in instantiation. I've done it myself. In production (but it was a long time ago ;) )
如果您必须自己动手,请仔细阅读双重检查锁定习惯用法以及随之而来的问题,以了解单例实例化可能出现的问题。如果您的实例化很重要,那么在实例化中实际上很容易获得多个实例或竞争条件。我自己做过。在生产中(但它是很久以前的;))

