【发布时间】:2011-01-16 22:24:41
【问题描述】:
如果我有两个 webapp,它们的 web-inf/lib 目录中都有相同的第三方库 jar,比如 log4j .....当第一个 webapp 加载并创建 log4j 类时,这个类被加载到堆中。当第二个 webapp 加载并尝试加载 log4j 类时,它会在堆中找到该类并使用该类吗?或者它将自己的类副本加载到堆中?
【问题讨论】:
如果我有两个 webapp,它们的 web-inf/lib 目录中都有相同的第三方库 jar,比如 log4j .....当第一个 webapp 加载并创建 log4j 类时,这个类被加载到堆中。当第二个 webapp 加载并尝试加载 log4j 类时,它会在堆中找到该类并使用该类吗?或者它将自己的类副本加载到堆中?
【问题讨论】:
嗯,我认为这主要是一个 ClassLoader 问题,它仍然取决于您使用的应用程序服务器,但我猜他们中的大多数使用单个 JVM 并为每个正在运行的 webapp 保留一个 ClassLoader,以便您可以使用不同的 webapp同一 jar/clases 的不同版本一起运行。
例如,在 tomcat 中,如果您需要一些共享库,您可以使用 /tomcat/shared/lib 文件夹,您可以在其中放置所有 Web 应用都可以访问的所有 jar。
否则是的,不同的 webapp 不会共享同一个堆,这意味着 webapp 可以访问由运行在同一应用程序服务器中的其他 webapp 创建的对象
【讨论】:
不,不应该。
在堆上加载的事实类在这里没有任何意义。因为每个类加载器都维护自己加载的类列表。
但是,类加载器也被组织成一棵树,它们应该要求其父类加载器首先尝试加载类,如 ClassLoader 类的 javadoc 中所述。
ClassLoader 类使用委托模型来搜索类和资源。 ClassLoader 的每个实例都有一个关联的父类加载器。当请求查找类或资源时,ClassLoader 实例将在尝试查找类或资源本身之前将对该类或资源的搜索委托给其父类加载器。
但是,网络服务器通常不遵循这种委托模型,以避免网络服务器本身使用的库被网络应用程序拾取。 (此行为有时是可配置的,但这取决于您使用的网络服务器。)
所以实际上每个 webapp 都应该有自己独立的类空间,独立于所有其他 webapp,因此它们甚至可以毫无问题地使用同一个库的两个不同版本。
另一个重要的教训是,由两个不同的类加载器加载的同一个类文件实际上是堆中的两个独立类,一个类的对象将与另一个类不兼容。
【讨论】: