如何在 Web 应用程序中处理单例?
据我所知,单例基本上是当你有一个私有成员,它表示你想要有一个实例的对象。然后在构造函数中初始化成员对象。
此对象的所有引用都是通过公共属性完成的,而公共属性仅引用已实例化的私有成员。
现在,在 Web 应用程序中,这是如何工作的?单个实例是否只是在容器中徘徊(比如 tomcat),直到 tomcat 关闭?
据我所知,单例基本上是当你有一个私有成员,它表示你想要有一个实例的对象。然后在构造函数中初始化成员对象。
此对象的所有引用都是通过公共属性完成的,而公共属性仅引用已实例化的私有成员。
现在,在 Web 应用程序中,这是如何工作的?单个实例是否只是在容器中徘徊(比如 tomcat),直到 tomcat 关闭?
如果您的执行环境使用多个类装入器,那么每个类实例将获得一个单例。如果你的单例类被加载到不同的类装入器中,那么它实际上是两个不同的类,然后会有两个“单例”实例。
您可以在文档中找到有关 Tomcat 类装入器的一些信息。
应该区分单例模式及其实现。大多数(如果不是全部)常见的 Singleton 实现都存在上述类加载问题以及序列化、线程安全等问题。有关非常全面的概述,请参阅 https://www.securecoding.cert.org/confluence/display/java/MSC07-J.+Prevent+multiple+instantiations+of+singleton+objects。
但是,最广泛意义上的单例模式可以是在特定上下文中保证是唯一的任何服务。单例的唯一性只能相对于给定的作用域(如类装入器,JVM,容器或集群)指定;唯一性级别取决于实现,应根据应用程序的要求选择实现。
导致使用单例的两个非常常见的要求是依赖注入(c.q.使用工厂)和内存中缓存。在这两种情况下,都有好的框架可以向客户端隐藏单例方面,并在例如企业应用程序容器中提供足够级别的唯一性。对于依赖注入 Spring,我想到了 Guice 或 Pico。对于缓存,我知道Ehcache是领先的解决方案,但肯定还有更多。(有趣的琐事:“ehcache”这个名字是一个回文)
一般来说,单例的使用是“不受欢迎的”,并被视为一种反模式。另一方面,依赖关系注入和缓存等服务需要唯一性才能工作。因此,如果我们宣称自己是反辛格尔顿的,同时使用Spring或Ehcache或类似的东西,我们就是在自欺欺人。
在我看来,对单例的恐惧源于许多可能的糟糕实现,而且很多。即使 Singleton 实现本身是“安全的”,在整个应用程序中直接调用它(通过静态访问)也会导致紧密耦合和较差的可测试性。
如果应用程序中有 Singleton 工厂,则可以进行的一项改进是重构其客户端,以便它们不会在需要依赖项时调用工厂,而是提供一个私有字段和一个允许注入依赖项的公共 setter。然后,您可以集中客户端的初始化,也许在同一工厂中,并使客户端代码保持干净,松散耦合和可测试(您现在可以注入模拟依赖项)。这也可能是引入像Spring这样的依赖注入框架的第一步。
我希望在这个相当长和漫无边际的帖子的某个地方,我帮助回答了你的问题!(-;