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

问题描述:

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

但是,这对我来说似乎很奇怪,即两个不同的应用程序可以使用此方法共享上下文。有人能帮我理解为什么这样。例如在下面的代码中,两个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"); 
    } 
} 
+1

我不明白这个问题:你自己解释一下,Tomcat的系统类加载器中的类是在所有应用程序之间共享的。因此,这两个应用程序访问相同的类,从而读取相同的静态字段,并可以看到彼此的效果。 – 2010-03-10 12:04:22

+0

是的,但我觉得两个独立的应用程序可以以这种方式共享上下文。事实上,如果他们有相同的类实例,他们甚至可以在两个不同的应用程序中实现多线程/同步,这看起来非常不直观。 – saugata 2010-03-10 12:12:44

正如评论说,你已经正确地解释了为什么你观察你观察到的行为。

关键是如何构造ClassLoaders。一个JVM中的两个ClassLoader完全可以加载一个类,因此包含静态字段的单独独立副本。 “静态”使一个ClassLoader,而不是一个JVM'全球'。我想,Tomcat不能拥有带共享库的容器级ClassLoader,并且强迫每个应用程序ClassLoader单独加载共享库。

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

这就是为什么你不应该把应用程序依赖关系放在Tomcat的共享库文件夹中。这是'解决方案'。它将应用程序绑定到容器的特定设置和部署,这违背了J2EE Web应用程序的原则。只需为每个应用程序在WEB-INF/lib中放置依赖关系的副本。

您观察到的行为是另一个不这样做的原因:应用程序变得彼此间隔较小。它不会让我成为违反直觉的行为,但是这只是因为我习惯了Tomcat的工作方式并思考这些事情。

+0

我遇到了类似的问题,我需要在两个webapps之间共享对象。在我看来,将对象放入系统类加载器可能是唯一的解决方案。看到http://*.com/questions/9453109/using-jndi-to-share-servlet-session-objects-and-data-in-tomcat – ziggy 2012-02-27 14:07:25

+1

也许......但跨webapps共享绝对不是你的东西打算这样做。 (尽管查看.ear文件)出于上述原因,它可能正常工作,但无法保证正常工作。 – 2012-02-28 15:37:19