【问题标题】:Force a custom ClassLoader for WAR files?强制为 WAR 文件使用自定义 ClassLoader?
【发布时间】:2011-09-20 15:11:48
【问题描述】:

是否有一种标准方式(即由一些 Java/J2EE/etc. 规范定义)为 Java Servlet 容器提供自定义类加载器,该容器应该用于加载 WAR 文件?

在一个新项目中,我们正在扩展一个带有 Web 服务的大型商业 Java 软件包 (Foo),这需要一定的部署灵活性(作为单独的服务等)。特别是,我们希望避免在每个 WAR 文件中包含所有 Foo 软件依赖 Jar 文件的必要性,因为它们数量众多且很大,并且会随着我们开发的补丁/错误修复版本而改变。同样,非常不希望将所有依赖项复制到每个 Servlet 容器的“lib”目录中。

理想情况下,我想告诉 Java 应用程序服务器这些 WAR 文件必须使用我将提供的自定义类加载器来加载,该类加载器会自动包含 Foo 软件依赖项 Jars。像这样的东西(在 Java 伪代码中):

public class MyWarFileClassLoader extends ClassLoader {
  protected URLClassLoader urlcl;
  public MyWarFileClassLoader(File warFile) {
    File installDir = System.getEnv("FOO_HOME");
    List<File> fooEntries = new File(installDir, "jars").listFiles("*.jar");
    fooEntries.add(new File(installDir, "resources"));
    fooEntries.add(warFile);
    this.urlcl = new URLClassLoader(fooEntries);
  }
  public Class<?> findClass(String name) {
    return this.urlcl.findClass(name);
  }
}

如果没有标准方法来做到这一点,是否有一种直接的方法可以为多个 WAR 文件实现相同的目标,而不管目标 Servlet 容器是什么?

[编辑]

换句话说:是否有一种通用模式允许 WAR 文件在运行时管理它们自己的依赖项,而不是依赖于 Servlet 容器配置?当然,我可以让 WAR 文件清单包含一个 Class-Path 属性,但是这些条目在构建时仍然是“硬编码”的,而不是在运行时自动检测到。

【问题讨论】:

    标签: java jakarta-ee classloader war


    【解决方案1】:

    没有标准方法可以强制在 Java EE 应用程序中使用特定的自定义类加载器来从预定义的源加载类。但是,可以在 Java EE 应用程序中捆绑库,以便多个模块(包括驻留在 WAR 中的 Web 模块)可以加载和访问捆绑库中的类。

    Java EE 规范允许企业应用程序部署(.ear 文件)将库捆绑到库部署目录中;默认情况下,这是.ear 文件中的lib 目录。然后,这些库可以被.ear 文件根目录中的多个 web 模块(位于不同的.war 文件中)使用。 Java EE 6 规范的相关部分是第 EE 8.2.1 节,其中声明如下:

    .ear 文件可能包含一个目录,该目录包含打包在 JAR 文件中的库。 .ear 文件的部署描述符的 library-directory 元素包含此目录的名称。如果未指定library-directory 元素,或者.ear 文件不包含部署描述符,则使用名为lib 的目录。空的library-directory 元素可用于指定没有库目录。

    此目录(但不是子目录)中带有.jar 扩展名的所有文件都必须可供打包在 EAR 文件中的所有组件使用,包括应用程序客户端。这些库可以使用此处描述的任何技术引用与应用程序捆绑或单独安装的其他库。

    请务必注意,所有符合 Java EE 的应用程序服务器(WebLogic/WebSphere/JBoss 等)都支持使用捆绑库部署 EAR 文件。但是,有些 servlet 容器(如 Tomcat 和 Jetty)不符合整个 Java EE 规范;此类容器将不支持 EAR 文件的部署。

    如果库需要被 servlet 容器中的多个 Web 模块访问(由于容器的选择或由于对 WAR 文件的偏好),您应该依赖 servlet 容器支持共享库以在没有库的情况下部署 WAR 文件。 Java EE 规范在这方面没有强制要求有关使用已安装库的任何要求。通过支持版本化的共享库(部署的应用程序可能只使用多个版本中的一个),一些容器比其他容器更好地支持共享库,而其他容器(如 Tomcat)则不支持。

    【讨论】:

    • 感谢您提供此信息,Vineet,非常有趣。我会细化我的问题,特别提到 Servlet 容器,因为我们不需要完整的 AppServer。
    • @maerics,我的回答将继续保持不变,除了您可能依赖 tha JAR 清单中的 Extension-List 属性来允许加载共享库(这仍然是以适用于每台服务器的方式安装在服务器中)。您可能需要阅读 Java EE 6 规范中关于库支持的整个部分(第 8.2 节)。
    猜你喜欢
    • 2011-05-05
    • 2017-01-18
    • 1970-01-01
    • 1970-01-01
    • 2018-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多