Java 当同一个类存在于同一服务器上的不同应用程序中时,类加载是如何工作的?

Java 当同一个类存在于同一服务器上的不同应用程序中时,类加载是如何工作的?,java,jakarta-ee,classloader,war-filedeployment,Java,Jakarta Ee,Classloader,War Filedeployment,我在一个应用服务器上运行多个web应用,每个web应用WAR文件都包含同一jar文件的副本 这是否意味着jar文件中的一个类将在JVM中加载多次,每个WAR文件一次?接下来,如果我在这样一个类中有一个静态同步方法,那么它是否只在它所在的web应用程序中的线程之间同步,而不是在不同WAR文件中的不同jar文件中的同一个类中的同一个方法上同步?(希望问题有意义,必要时予以澄清) 如果是这种情况,我认为最好的解决方案是从每个WAR文件中删除jar文件,并将其部署到服务器上的共享类路径文件夹中?大多数应

我在一个应用服务器上运行多个web应用,每个web应用WAR文件都包含同一jar文件的副本

这是否意味着jar文件中的一个类将在JVM中加载多次,每个WAR文件一次?接下来,如果我在这样一个类中有一个静态同步方法,那么它是否只在它所在的web应用程序中的线程之间同步,而不是在不同WAR文件中的不同jar文件中的同一个类中的同一个方法上同步?(希望问题有意义,必要时予以澄清)


如果是这种情况,我认为最好的解决方案是从每个WAR文件中删除jar文件,并将其部署到服务器上的共享类路径文件夹中?

大多数应用程序服务器使用最特定的路径优先策略。
如果你有多个库,他们也会做同样的事情,你应该考虑把它们放在应用服务器LIB(F.E:ToCCATHOME/LIB)

< P> java EE应用服务器通常使用多个类加载器来隔离应用程序,并允许一个应用程序的新版本部署而不影响其他应用程序。 您可以在一个EAR中获得一些模式,例如几个WAR文件和一个EJB文件,其中包含类装入器的层次结构,每个WAR都有自己的模式

正如您所描述的,这确实会导致重复,但这并不一定是一件坏事。这意味着您甚至可以同时部署同一JAR的不同版本,这实际上可能是有益的,允许增量迁移到新版本

一些应用服务器(WebSphere for exmaple)明确支持共享库概念,我确实使用了它


谨防将JAR弹出到任意类路径中,这样会有破坏应用程序服务器本身稳定性的风险。

Java类加载器通常通过在一个或多个位置以固定顺序查找类来工作。例如,从命令行运行应用程序时加载应用程序的类加载器首先查看
rt.jar
文件(以及bootclasspath上的其他文件),然后查看类路径指定的目录和jar文件

webapp类加载原则上类似,但在实践中要复杂一些。对于特定的webapp,webapp的类加载器按以下顺序查找类。例如,Tomcat 6按以下顺序查找类:

  • JVM的引导类
  • 系统类加载器类(已描述)
  • /WEB-INF/webapp的类
  • /webapp的WEB-INF/lib/*.jar
  • $CATALINA_HOME/lib
  • $CATALINA_HOME/lib/*.jar
  • 当然,一旦类加载器找到了它要查找的类,它就不再查找了。因此,在顺序后面具有相同名称的类将不会被加载

    复杂的是web容器对于每个webapp都有一个类加载器,这些类加载器委托给其他管理公共类的类加载器。实际上,这意味着对于整个容器(例如1和2),某些类只加载一次,而其他类可能被不同的类加载程序加载多次

    (当一个类被多次加载时,它会导致不同的
    class
    对象和不同的类静态。就JVM而言,类的版本是不同的类型,不能从一个版本类型转换到另一个版本。)

    最后,可以将Tomcat配置为允许单个Web应用程序“热加载”。这需要停止一个webapp,为它创建一个新的类加载器,然后重新启动它

    跟进

    所以。。。同步静态方法不会保护对已多次加载类的共享资源的访问

    这取决于细节,但可能不会。(或者从另一个角度看,如果一个类实际上已被加载多次,那么该类的每个“加载”的
    static
    方法将访问一组不同的
    static
    字段。)


    如果您真的希望一个单例应用程序类实例由同一容器中的多个webapps共享,那么将该类放入
    $CATALINA_HOME/lib
    或等效文件中是最简单的。但是你也应该问问自己,这是否是一个好的系统设计。考虑合并Web应用程序,或者使用请求转发等代替共享数据结构。在webapps中,单例模式往往很麻烦,这种风格甚至更麻烦。

    Tomcat也支持共享库。。。JBoss的$CATALINA_HOME/libAs中:它支持“类存储库”。您可以配置JBoss以查看来自其他WAR的类。但这只会导致一些问题,如内存泄漏和永久空间错误,当一些战争被错误地取消部署时。谢谢你的回复。是的,既然你提到了演员的问题,我以前也遇到过这个问题。因此,为了回答我的问题,同步静态方法不会保护对已多次加载类的共享资源的访问?@Stephane C当我处理部署在Tomcat中的多个Web应用程序时,我遇到了一个链接异常(资源已加载到不同的类加载程序中)。我通过将资源移动到TC/bin dir来解决这个问题,以便TC Cloader加载它并解决这个问题。你知道我为什么会犯这样的错误吗?为什么同一资源不能由两个不同webapp的两个不同类加载器加载?在这个答案中,可以看出不同的WAR类加载器会导致“相同”类的不同类版本,即。E从e加载类
    a
    时。G
    WEB-INF/lib
    中的JAR
    a.JAR
    ,在同一服务器(或EAR)上的不同战争中作为完全相同的文件分发。当我想在类
    a
    实例的服务器(或EAR)上构建一个跨越所有WAR的缓存时,这将不起作用(除非我移动JAR
    a.JAR