【问题标题】:Classloader behaviour on Tomcat with multiple applications具有多个应用程序的 Tomcat 上的类加载器行为
【发布时间】:2010-03-10 11:39:35
【问题描述】:

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

但是,我觉得这有点奇怪,两个不同的应用程序可以使用这种方法共享一个上下文。有人可以帮我理解为什么会这样。例如在下面的代码中,两个 servlet 分别部署在单独的战争中,而 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");
    }   
}

【问题讨论】:

  • 我不明白这个问题:你自己解释说Tomcat的系统类加载器中的类在所有应用程序之间共享。因此,两个应用程序访问同一个类,从而从相同的静态字段中读取,并且可以看到彼此的效果。
  • 是的,但在我看来,两个独立的应用程序可以以这种方式共享一个上下文,这与我的直觉相反。事实上,如果他们有相同的类实例,他们甚至可以跨两个不同的应用程序实现多线程/同步,这似乎非常违反直觉。

标签: java tomcat classloader


【解决方案1】:

正如 cmets 所说,您已经正确解释了为什么观察到您观察到的行为。

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

但这对于 J2EE API 和实现等其他常见类来说有点浪费。原则上,类不应该依赖于这个 ClassLoader 结构。

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

您观察到的行为是不这样做的另一个原因:应用之间变得不那么孤立了。我并不认为这是违反直觉的行为,但我想这只是因为我习惯了 Tomcat 的工作方式和思考这些事情的方式。

【讨论】:

  • 我遇到了类似的问题,我需要在两个 webapps 之间共享对象。在我看来,将对象放在系统类加载器中可能是唯一的解决方案。见stackoverflow.com/questions/9453109/…
  • 也许...但是跨网络应用程序共享绝对不是您打算这样做的事情。 (尽管查看 .ear 文件)它可能会起作用,但不能保证会起作用,原因如上所述。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-09
  • 2011-01-11
  • 2014-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多