【问题标题】:How Tomcat Classloader separates different Webapps object scope in same JVM?Tomcat Classloader 如何在同一个 JVM 中分离不同的 Webapps 对象范围?
【发布时间】:2013-10-24 07:07:52
【问题描述】:

由于 Tomcat 可以同时加载多个 webapp,并且这些 webapp 可以单独工作,互不干扰,并且工作在同一个 JVM 中。 所以我很困惑tomcat如何处理同一个JVM中的对象范围。

例如,我在两个不同的 Web 应用程序中都有一个单例对象,而 tomcat 将为每个生成两个不同的单例对象。我一直认为单例对象在同一个JVM中只有一个对象,但在tomcat JVM中可能有两个或更多。


我已经阅读了一些关于 ClassLoader 的信息,Tomcat 有自己的 WebAppClassLoader 来加载 webapps。那么这是否意味着这里的对象范围是 ClassLoader 还是我错了。有谁知道这个或者可以给我一些关于tomcat工作内存布局的信息?

【问题讨论】:

    标签: java tomcat jvm


    【解决方案1】:

    所有的秘密都在这些 ClassLoader 实例背后。

    类的状态(如所有静态变量、字节码等)由加载该类的类加载器确定(在 JVM 中,类通过其完全限定的名称和加载该类的类加载器来标识。这不完全是一个范围,但作为范围思考通常有助于更好地理解这一点)。

    所以如果一个类被两个不同的类加载器加载,这个类在虚拟机中存在两次,它有两组静态字段,可以有不同的字节码(比如不同的方法实现)等等。请注意,即使它们的名称相同,这两个对象也不能相互转换。 “普通”Java 应用程序的所有类都由类加载器层次结构加载,并且每个类只加载一次。

    对于更复杂的场景,您将需要不同的行为。有时您希望将库与您的代码隔离开来(例如 eclipse 中的插件或应用程序服务器中的 Web 应用程序)。

    将您的程序与其他类隔离的基本思想是使用额外的类加载器加载那些类并使用大量反射。如果您想阅读此内容,请查看 Oracle 在 ClassLoadersOSGI 上的文档。

    Tomcat(以及许多其他 Web 容器/应用程序服务器)使用单独的 ClassLoader 层次结构加载应用程序。这将所有类与其他(Web)应用程序隔离开来,从而确保单例、不同的类版本和所有这些东西不会发生冲突。

    【讨论】:

      【解决方案2】:

      请记住,Java 中的类由其完全限定名称加载它的类加载器标识。 Tomcat 为您部署的每个上下文(Web 应用程序)使用单独的类加载器,从而使它们保持独立。此外,系统类加载器加载tomcat特定库,JVM引导加载器加载Java核心库。

      【讨论】:

        【解决方案3】:

        在谈论单例时总是被忽略的一件事是,单例每个类加载器只能有一个实例。 ClassLoader 限制了类的可见性,因此同一类可以存在于同一 VM 中的多个不同类加载器下。这允许您同时加载不同版本的 jar。

        这个问题:Java Class Loaders 似乎有一些不错的链接和资源可供进一步学习。

        【讨论】:

        • 很好地提到了一个类的多个实例的实际需要 - 共存的库版本
        【解决方案4】:

        在普通 Java 应用程序中,当要求类加载器加载一个类时,它首先将请求委托给它的父类加载器,然后在父类加载器找不到请求的类时加载它。

        对于 Web 应用程序服务器,这略有不同。对于部署在像 tomcat 这样的 Web 应用程序服务器中的每个 Web 应用程序,通常有不同的类加载器。对于 Tomcat,它如下所示 -

        所以对于网络应用程序类加载资源按以下顺序发生 -

        1. JVM 的引导类(核心 java 类)
        2. /WEB-INF/Web 应用程序的类
        3. /WEB-INF/lib/*.jar 您的 Web 应用程序
        4. 系统类加载器类(Tomcat / Classpath 特定类)
        5. 通用类加载器类(所有网络应用通用的类)

        但请注意,如果 Web 应用程序类加载器配置为 delegate="true",那么顺序会更改 -

        1. JVM 的引导类(核心 java 类)
        2. 系统类加载器类(Tomcat / Classpath 特定类)
        3. 通用类加载器类(所有网络应用通用的类)
        4. /WEB-INF/Web 应用程序的类
        5. /WEB-INF/lib/*.jar 您的 Web 应用程序

        有关更多详细信息,您可以查看 Apache Tomcat 的 Class Loader HOW-TO 页面。

        【讨论】:

          【解决方案5】:

          JVM 中类的“ID”由完全限定的类名和用于加载它的类加载器组成。这意味着,如果您通过不同的类加载器加载两个具有相同名称的类,它们将被视为不同的类。

          【讨论】:

            【解决方案6】:

            所以对于类加载器来说,单例就是单例——在容器/JVM 中;作为一个容器/JVM 可能有多个类加载器。

            【讨论】:

              【解决方案7】:
              1. tomcat 中的不同应用程序使用不同的类加载器来分隔。例如 app1 使用 ClassLoaderA,app2 使用 classloaderB。
              2. 每个类都将使用自己的类加载器来加载其他类。因此,如果 ClassA.class 引用 ClassB.class 那么 ClassB 需要位于 ClassA 的类加载器或其父级的类路径上。例如在 app1 中,com.exmaple.test1 从 ClassLoaderA 加载。而 com.exmaple.test1 想要新的 com.exmaple.test2()。默认情况下,它使用自己的类加载器 ClassLoaderA 来加载 com.exmaple.test2。所以在 com.exmaple.test1 的视图中它只能看到它自己的类路径的类(app1/webapp/classes 或 app1/webapp/lib)。而在 app2 中,它会看到不同的视图。
              3. 总而言之,学习类加载器你必须了解委托模型。可见性是孩子可以看到父母。但是父母看不到孩子,兄弟姐妹看不到兄弟姐妹。这样我们就可以隔离不同的应用了。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2013-03-02
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2012-05-09
                • 2012-04-06
                • 2017-08-14
                相关资源
                最近更新 更多