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

Cod*_*ber 32 java classloader java-ee war-filedeployment

我在应用服务器上运行了多个Web应用程序,每个Web应用程序WAR文件都包含相同jar文件的副本.

这是否意味着该jar文件中的一个类将在JVM中多次加载,对于它存在的每个WAR文件一次?接下来,如果我在这样的类中有一个静态同步方法,它是否只在它存在的web-app中的线程之间同步,而不是在不同jar文件中的同一个类中的同一方法同步WAR文件?(希望这个问题有道理,必要时会澄清).

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

Ste*_*n C 34

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

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

  1. JVM的Bootstrap类
  2. 系统类加载器类(在此描述)
  3. / WEB-INF/webapp的类
  4. webapp的/WEB-INF/lib/*.jar
  5. $ CATALINA_HOME/lib目录
  6. $ CATALINA_HOME/lib目录/*.JAR

当然,一旦类加载器找到它正在寻找的类,它就不会再看了.因此,订单中稍后具有相同名称的类将不会被加载.

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

(当一个类被多次加载时,它会产生不同的Class对象和不同的类静态.就JVM而言,类的版本是不同的类型,你不能从一个版本转换为另一个版本.)

最后,Tomcat可以配置为允许单个webapps"热负载".这需要停止webapp,为它创建一个新的类加载器,然后重新启动它.

跟进

那么......同步静态方法不会保护对多次加载类的共享资源的访问?

这取决于细节,但可能不会.(或者,如果另一种方式,如果一个类实际上已经多次加载,那么static该类的每个"加载"的方法将访问一组不同的static字段.)

如果您确实希望单个应用程序类实例由同一容器中的多个Web应用程序共享,则最简单的方法是将类放入$CATALINA_HOME/lib或等效.但你也应该问问自己这是不是很好的系统设计.考虑组合webapps,或使用请求转发等而不是共享数据结构.单例模式在webapps中往往很麻烦,而且这种风格更是如此.


djn*_*jna 5

Java EE应用程序服务器通常使用多个类加载器将应用程序彼此隔离,并允许在不影响其他应用程序的情况下部署一个应用程序的新版本。

您可以在EAR中获得带有多个类加载器层次结构的模式,例如多个WAR文件和一个EJB文件,每个WAR都有它自己的。

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

一些应用程序服务器(WebSphere for exmaple)具有对共享库概念的显式支持,我确实使用了它。

请注意,只要将JAR弹出到任意类路径中,就有可能破坏应用服务器本身的稳定性。