具有多个应用程序的 Tomcat 上的类加载器行为

2023-11-26

在 Tomcat 5.5 服务器上,我将一个类放入系统类路径中(并修改 catalina.bat 以选择它),或者将类放入共享 lib 目录中。现在,如果我有两个不同的应用程序使用同一个类,而它们的 WEB-INF lib/classes 目录中没有该类,那么它们将使用该类的相同实例。我理解这样的概念:如果找不到类,类加载器将委托给其父类加载器来查找类,因此在这种情况下,由于该类不存在于 WEB-INF/classes 或 WEB-INF/lib 中WebAppX 类加载器将分别尝试共享、通用和系统类加载器。

然而,这对我来说似乎很奇怪,两个不同的应用程序可以使用此方法共享上下文。有人可以帮助我理解为什么会这样吗?例如在下面的代码中,两个 servlet 分别部署在单独的 war 中,而 CommonCounter 是共享的,并且它们可以读取对方递增的计数器值。

Edit

对我来说,两个独立的应用程序可以以这种方式共享上下文似乎是违反直觉的。事实上,如果它们具有相同的类实例,它们甚至可以在两个不同的应用程序之间实现多线程/同步,这似乎非常违反直觉。

package com.test;
public class CommonCounter {

    public static int servlet1;
    public static int servlet2;
}




public class Servlet1 extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        CommonCounter.servlet1++;
        System.out.println("Other one had "+CommonCounter.servlet2+" hits");
    }   
}



public class Servlet2 extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        CommonCounter.servlet2++;
        System.out.println("Other one had "+CommonCounter.servlet1+" hits");
    }   
}

正如评论所说,您已经正确解释了您观察到的行为的原因。

关键是类加载器的结构。一个 JVM 中的两个类加载器完全有可能分别加载一个类,因此包含单独的、独立的静态字段副本。 “静态”使某些东西对于类加载器(而不是 JVM)来说是“全局”的。我认为 Tomcat 无法容纳带有共享库的容器级 ClassLoader,并且以某种方式强制每个应用程序 ClassLoader 单独加载共享库。

但这对于其他常见类(例如 J2EE API 和实现)来说有点浪费。原则上,类无论如何都不应该依赖于这个 ClassLoader 结构。

这就是为什么您不应该将应用程序依赖项放在 Tomcat 的共享库文件夹中。这就是“解决方案”。它将您的应用程序与容器的特定设置和部署联系起来,这违反了 J2EE Web 应用程序的原则。只需将每个应用程序的依赖项副本放入 WEB-INF/lib 中即可。

您观察到的行为是不这样做的另一个原因:应用程序之间的隔离程度降低。我并不认为这是违反直觉的行为,但我认为这只是因为我习惯了 Tomcat 的工作方式和思考这些事情的方式。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

具有多个应用程序的 Tomcat 上的类加载器行为 的相关文章

随机推荐