是否有标准方法(即由某些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
属性,但是这些条目在构建时仍然是“硬编码的”,而不是在运行时自动检测到。
答案 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)则不支持。