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

标签 java tomcat classloader

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

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

编辑

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

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 中的两个 ClassLoader 完全有可能各自加载一个类,因此包含单独的、独立的静态字段副本。 “静态”对 ClassLoader 来说是“全局的”,而不是 JVM。我想,Tomcat 无法保存带有共享库的容器级 ClassLoader,并以某种方式强制每个应用程序 ClassLoader 单独加载共享库。

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

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

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

关于java - 具有多个应用程序的 Tomcat 上的类加载器行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2416517/

相关文章:

java - onClickListener()的设置方式

java - 泛型中类型参数中的常量

java - Web 应用程序中的静态变量是否会导致内存泄漏(从角度来看是 OutOfMemory)?

java - 类加载器和服务加载器。使用哪个类加载器?

java - 如何强制 Jetty 的 Maven 插件关闭其文件句柄?

postgresql - 臭名昭著的 java.sql.SQLException : No suitable driver found

java - Spring +AngularJs + Tomcat 9.0 - 发送PUT请求时出现403错误

java - 如何在jboss部署中检查classloader类层次结构(优先级)

java - 无法通过类型转换为类型

java - Gson.toJson() 项目排序错误