如果我在单个 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 类路径上找到它,如果找不到该类,它会要求父类加载器加载该类。
单例通常与ClassLoader
only 相关联。
因此,如果您有一个基于 .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>