24

如果我在单个 Tomcat 实例(或任何其他服务器)上部署并运行相同应用程序的 2 个实例。然后将创建一个(单例类的)对象:

  1. 跨 Tomcat 的单个实例(但对于同一应用程序的 2 个实例很常见)或
  2. 跨应用程序实例(2 个应用程序实例不同)

所以本质上我想了解每个 JVM 创建一个 Singleton 类的对象总是这样的情况吗?如果应用程序托管在 Web 服务器(或容器)上,这将如何工作。

4

5 回答 5

35

如果您有一个单例类并且您在 Tomcat 中运行两个使用该类的 Web 应用程序,那么这两个 Web 应用程序将在运行 Tomcat 的 JVM 中获得该单例的 2 个不同实例。

但是如果您的 webapp 将使用来自 JRE 或 Tomcat 共享库的单例,例如 Runtime.getRuntime webapps 将获得相同的 Runtime 实例。

这是因为 Tomcat 为 webapps 使用单独的类加载器。当 webapp 类加载器加载一个类时,它首先尝试在 webapp 类路径上找到它,如果找不到该类,它会要求父类加载器加载该类。

于 2013-07-18T10:58:28.030 回答
22

单例通常与ClassLoaderonly 相关联。

因此,如果您有一个基于 .war 文件中的 .class 文件的单例,并且您多次部署此 Web 应用程序,每个应用程序都会获得自己的单例。

另一方面,如果您的单例的 .class 文件位于 的类路径中tomcat,那么您只有一个实例。这个 .class 不属于特定的 Web 应用程序(它属于tomcat实例)。

如果您在两个位置都有单例,则它取决于类加载器层次结构,您可以在“父优先”或“Web 应用优先”之间进行选择。

于 2013-07-18T11:04:10.160 回答
5

通过确保您始终为单例查询相同ClassLoader的内容,可以创建这样的单例。我在另一个答案中写了一个广泛的解释。

于 2014-08-12T20:27:57.530 回答
4
  • Tomcat 为每个 Web 应用程序创建新的类加载器。
  • 因此,如果您的 Singleton 类存储在 war 文件中,则同一个 war 文件将在 Tomcat 容器中具有两个实例,即它为每个 war 文件创建两个单独的 Singleton 类。
  • 如果 Singleton 类位于 Tomcat 的共享库路径中,则 Tomcat 只会为这两个应用程序创建一个 Singleton 实例。

JVM类比:

JVM就像大宅。它包含与服务器和库的组合系列。

ClassLoader 是家族成员,每个家族成员代表一个 ClassLoader(作为委托层次结构而不是继承层次结构)。注意:ClassLoader 是类,它可以创建多个实例。

应用程序就像电器。例如:洗衣机、冰箱、冷风机、电视、餐桌、沙发等……

每个图书馆都有自己的图书馆。每个人都在父母的图书馆中搜索,如果找不到,则在自己的图书馆中搜索。

限制:如果父亲买了一个电器,他们的孩子可以使用它,但他的父母和兄弟姐妹不能使用它。每个应用程序可能使用相同库的不同版本。即如果图书馆包含相同书籍的两个或多个版本,它会选择最先可用的书籍。

每个家庭号码只能使用一个唯一的设备。

在家里,我们可以使用多个相同版本的电器。因此,JVM 允许我们运行多个相同版本的应用程序。

Garbage Collector是Mansion中的仆人,作为守护进程漫游,可以清除任何类型的对象。

静态变量的范围限制为每个 ClassLoader 一个。

于 2016-09-14T14:33:11.840 回答
1

<shakey-ground>据我所知,每个类加载器的单例都是唯一的。所以我认为你的问题的答案取决于容器加载 Web 应用程序的方式。

如果它为每个 Web 应用程序分配一个类加载器,那么您似乎会得到两个完全独立的单例对象。如果它分配了一个类加载器并且所有 Web 应用程序都使用它,那么它们共享同一个单态实例。</shakey-ground>

于 2013-07-18T10:58:36.060 回答