【问题标题】:Singleton across JVM or Application instance or Tomcat instance跨 JVM 或 Application 实例或 Tomcat 实例的单例
【发布时间】:2013-07-17 06:34:09
【问题描述】:

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

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

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

【问题讨论】:

    标签: java tomcat jvm webserver singleton


    【解决方案1】:

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

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

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

    【讨论】:

    • @Evgenniy,这是否意味着在我的单个应用程序中我可以使用不同的类加载器创建 2 个单例对象(只是一个想法)。??
    • 是的,创建 2 个类加载器(你可以使用 URLClassLoader),用 ClassLoader.loadClass(className) 加载同一个类 - 你会得到 2 个不同的类实例
    • 这是否意味着单例已损坏?
    • 不,这要归功于在不同类加载器中运行的不同服务器应用程序的行为就像它们在两个独立的 JVM 中运行一样
    • 完美答案!
    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      单例通常只绑定到ClassLoader

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

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

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

      【讨论】:

      • @Beryllium “tomcat 的类路径”是什么意思?我的意思是我应该在哪里 pur 我的类/jar 以便我在应用程序中获得单例。
      • @vipin 我不能确定,因为我最近没有这样做,但是尝试将 .jar 文件放入 tomcat 的 lib/ 目录中。至于 JBoss 7,他们实际上也是这样做的,只是将其组织为“模块”。
      • @Beryllium 很久以前我读过一篇文章说我们不应该将任何 jar 放在 tomcat/lib 中。最近我做了一些研究,发现我们可以使用 catalina.properties 的 shared.loader 属性。但不确定它是否有效。
      • @Beryllium 我指的是这篇文章mulesoft.com/tcat/tomcat-classpath。请阅读“问题:我希望多个应用程序共享一个 JAR 文件,并且我希望这个 JAR 文件驻留在 Tomcat 中。”它是否为所有 webapp 解决了一个实例的相同问题?
      • @vipin 除了 tomcat 的 lib/ 目录之外,我不知道共享库路径,但根据该文档,如果从那里加载一个类,你会得到一个单例。不管怎样,他们推荐它,所以试试看。
      【解决方案4】:

      可以通过确保始终为单例查询相同的ClassLoader 来创建这样的单例。我在另一个答案中写了extensive explanation

      【讨论】:

        【解决方案5】:
        • Tomcat 为每个 Web 应用程序创建新的类加载器。
        • 因此,如果您的 Singleton 类存储在 war 文件中,则同一个 war 文件将在 Tomcat 容器中具有两个实例,即它为每个 war 文件创建两个单独的 Singleton 类。
        • 如果 Singleton 类位于 Tomcat 的共享库路径中,则 Tomcat 只会为这两个应用程序创建一个 Singleton 实例。

        JVM 类比:

        JVM 就像大宅。它包含带有多个应用程序和库的组合系列。

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

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

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

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

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

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

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

        静态变量的范围仅限于每个 ClassLoader 一个。

        【讨论】:

          猜你喜欢
          • 2015-02-18
          • 1970-01-01
          • 2019-01-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-12-19
          • 2010-11-10
          • 2013-06-02
          相关资源
          最近更新 更多