从.war文件加载类的顺序

时间:2010-12-16 23:55:07

标签: java web-applications classloader

我在以下场景中有关于担保的问题(如果有的话)(注意问题不是“如何以不同的方式做到这一点?”,问题是真的关于以下情况下的类加载顺序(为了更好地理解类加载的工作原理)。

这是假设情景......有一个 .war 文件,它具有以下(部分)目录结构:

 WEB-INF/classes/com/acme/Bunny.class
 .
 .
 .
 WEB-INF/lib/acme.jar

两个 Bunny.class 文件都有导入引用来自 acme.jar 的其他类

WEB-INF / classes /...中的

Bunny.class 是唯一一个与 acme中的类具有相同名称/路径的类。罐

.jar 文件 acme.jar 还包含 com.acme.Bunny (并且没有使用特殊的类加载器技巧)

据我所知,Java规范保证在程序实际使用(或故意“手动加载类似”)之前不会加载类,这就是为什么如果你填充数千个.jar,在.war中,类加载器不会开始加载数万个类。

(编辑)

  

但是顺序呢?   上面例子中的两个类是   装?

本来应该措辞:

  

但它是如何决定哪一个   上面有两个类?

或类似的东西:)

有一个保证: com.acme.Bunny 应该在 com.acme ... 的任何其他类之前使用。

基本上,在维基百科上,写了以下内容:

  

最复杂的JAR地狱问题   在需要的情况下出现   完全复杂的优点   类加载系统。一个Java   程序不需要只使用一个   单个“平面”类加载器,但相反   可能由几个(或,在   事实上,无限数量的嵌套,   合作的类加载器。类   由不同的类加载器加载可能   不完全以复杂的方式进行交互   由开发人员理解,领导   无法解释的错误或错误。

所以我想知道:我可以确定 /classes/com/acme/Bunny.class 将在 .jar 中的之前进行分类加载em> WEB-INF / lib / dir与否?

6 个答案:

答案 0 :(得分:13)

所选答案错误。 Servlet规范版本2.4和3.0明确指出首先加载WEB-INF /类,然后加载WEB-INF / lib

Servlet 2.4:http://download.oracle.com/otn-pub/jcp/servlet-2.4-fr-spec-oth-JSpec/servlet-2_4-fr-spec.pdf - 第SRV.9.5节,最后一段

Servlet 3.0:http://download.oracle.com/otn-pub/jcp/servlet-3.0-fr-oth-JSpec/servlet-3_0-final-spec.pdf - 第10.5节,最后一段

Web应用程序类加载器必须从WEB-INF / classes加载类 首先是目录,然后是WEB-INF / lib目录中的库JAR。

答案 1 :(得分:8)

This question可能会有所帮助。

servlet规范对此很模糊。人们期望在“WEB-INF / lib”之前搜索“WEB-INF / classes”,但似乎由servlet容器来决定。您可以确定的是,容器应该始终先加载一个容器,因此您永远不应该在同一个容器中看到这两个类。搜索路径可以可配置,具体取决于您的容器。

抱歉,我不能更具体:欢迎来到多个servlet容器的世界。不要让我开始使用Websphere的趣味游戏。

答案 2 :(得分:2)

WEB-INF/lib/*.jar个文件和WEB-INF/classes目录都在同一个ClassLoader中。就好像您使用ClassPath中列出的所有jar启动了一个应用程序。由于需要解析类名,ClassLoader将找到与其资源匹配的第一个类。它搜索的确切顺序是不确定的 - 它取决于平台。

Java包旨在解决名称冲突问题,例如您所描述的内容。故意将类命名为与其自己的jar文件中捆绑的类相同,这绝不是一个好主意。更好的解决方案是扩展类并在代码中使用新版本。如果您需要更改该类的功能,那么您可能会研究Java面向方面编程的黑魔法。

答案 3 :(得分:1)

答案完全取决于使用的具体类加载器层次结构。虽然JVM将提供系统类加载器,但Java EE应用程序服务器通常使用自定义ClassLoader实现来隔离在单独的模块和应用程序中加载的类,并强制执行安全性问题。

ClassLoader API不对具体实现如何解析类请求施加任何规则。但是,WEB-INF / lib目录的 intent 允许bundling of app-specific libraries。我怀疑大多数人都希望在jar文件的根目录之后搜索lib目录中的jar文件。

我不知道Java EE规范虽然建立了这样的保证,但抽象的ClassLoader类的接口和文档肯定没有。

因此,假设您可以拥有一个Web容器,最终将从war文件的根层次结构中的jar文件而不是返回Bunny.class。

答案 4 :(得分:1)

这取决于部署war文件的容器。根据我的经验,WEB-INF / classes位置始终位于lib / on应用程序上下文的类加载器的类路径之前。

在部署者将战争扩展到容器后​​立即加载类。通常在加载上下文加载器侦听器servlet时,使用它加载应用程序的其余部分。它可以通过多种方式完成,例如通过引用默认servlet或加载spring上下文等。

因此应首先加载WEB-INF / classes / com / acme / Bunny.class。

答案 5 :(得分:0)

你似乎在混淆“之前”的两种不同感官。

按照使用顺序加载类。这是暂时的,是对“之前”更正确的使用。如果在Bar之前使用Foo,那么它将在Ba​​r之前加载。

你还在谈论是否将在“acme.jar”的com / acme / Bunny.class之前加载classes / com / acme / Bunny.class。第二个根本不会加载。类加载器将在类路径中查找com / acme / Bunny.class的第一个实例,在类中找到一个,然后停止查找。