如果我在单个 Tomcat 实例(或任何其他服务器)上部署并运行相同应用程序的 2 个实例。然后将创建一个(单例类的)对象:
- 跨 Tomcat 的单个实例(但对于同一应用程序的 2 个实例很常见)或
- 跨应用程序实例(2 个应用程序实例不同)
所以本质上我想了解每个 JVM 创建一个 Singleton 类的对象总是这样的情况吗?如果应用程序托管在 Web 服务器(或容器)上,这将如何工作。
如果您有一个单例类并且您在 Tomcat 中运行两个使用该类的 Web 应用程序,那么这两个 Web 应用程序将在运行 Tomcat 的 JVM 中获得该单例的 2 个不同实例。
但是如果您的 webapp 将使用来自 JRE 或 Tomcat 共享库的单例,例如 Runtime.getRuntime webapps 将获得相同的 Runtime 实例。
这是因为 Tomcat 为 webapps 使用单独的类加载器。当 webapp 类加载器加载一个类时,它首先尝试在 webapp 类路径上找到它,如果找不到该类,它会要求父类加载器加载该类。
单例通常与ClassLoaderonly 相关联。
因此,如果您有一个基于 .war 文件中的 .class 文件的单例,并且您多次部署此 Web 应用程序,每个应用程序都会获得自己的单例。
另一方面,如果您的单例的 .class 文件位于 的类路径中tomcat,那么您只有一个实例。这个 .class 不属于特定的 Web 应用程序(它属于tomcat实例)。
如果您在两个位置都有单例,则它取决于类加载器层次结构,您可以在“父优先”或“Web 应用优先”之间进行选择。
通过确保您始终为单例查询相同ClassLoader的内容,可以创建这样的单例。我在另一个答案中写了一个广泛的解释。
JVM类比:
JVM就像大宅。它包含与服务器和库的组合系列。
ClassLoader 是家族成员,每个家族成员代表一个 ClassLoader(作为委托层次结构而不是继承层次结构)。注意:ClassLoader 是类,它可以创建多个实例。
应用程序就像电器。例如:洗衣机、冰箱、冷风机、电视、餐桌、沙发等……
每个图书馆都有自己的图书馆。每个人都在父母的图书馆中搜索,如果找不到,则在自己的图书馆中搜索。
限制:如果父亲买了一个电器,他们的孩子可以使用它,但他的父母和兄弟姐妹不能使用它。每个应用程序可能使用相同库的不同版本。即如果图书馆包含相同书籍的两个或多个版本,它会选择最先可用的书籍。
每个家庭号码只能使用一个唯一的设备。
在家里,我们可以使用多个相同版本的电器。因此,JVM 允许我们运行多个相同版本的应用程序。
Garbage Collector是Mansion中的仆人,作为守护进程漫游,可以清除任何类型的对象。
静态变量的范围限制为每个 ClassLoader 一个。
<shakey-ground>据我所知,每个类加载器的单例都是唯一的。所以我认为你的问题的答案取决于容器加载 Web 应用程序的方式。
如果它为每个 Web 应用程序分配一个类加载器,那么您似乎会得到两个完全独立的单例对象。如果它分配了一个类加载器并且所有 Web 应用程序都使用它,那么它们共享同一个单态实例。</shakey-ground>