强制为WAR文件自定义ClassLoader?

mae*_*ics 4 java war classloader java-ee

是否有一种标准方法(即由某些Java / J2EE / etc.spec定义)为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);
  }
}
Run Code Online (Sandbox Code Playgroud)

如果没有标准的方法可以做到,那么无论目标Servlet容器是什么,是否都可以通过简单的方法来实现多个WAR文件的相同目标?

[编辑]

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

Vin*_*lds 5

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

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

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

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

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

如果需要由Servlet容器中的多个Web模块访问这些库(由于选择了容器或由于对WAR文件的偏好),则应该依赖servlet容器对共享库的支持部署不带库的WAR文件。Java EE规范在这方面对使用已安装的库的使用没有任何要求。一些容器通过支持版本共享库(其中已部署的应用程序可能仅使用多个版本中的一个版本)来支持共享库,而其他容器(例如Tomcat)则不支持。