为WAR文件强制自定义ClassLoader?

时间:2011-09-20 15:11:49

标签: java java-ee classloader war

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

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

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

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属性,但是这些条目在构建时仍然是“硬编码的”,而不是在运行时自动检测到。

1 个答案:

答案 0 :(得分: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规范;此类容器不支持部署EAR文件。

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