从.war文件加载类的顺序

在下面的场景中我有一个关于保证的问题(如果有的话)(请注意问题不是“如何以不同的方式执行此操作?”) ,问题实际上是关于以下情况下的类加载顺序(至更好地理解类加载的工作原理)。

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

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

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

WEB-INF / classes / …中的Bunny.class是唯一一个与acme.jar中的类具有相同名称/路径的类。

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

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

(编辑)

但是上面示例中的两个类的加载顺序又如何呢?

应该措辞:

但是如何确定上面两个类中的哪一个被加载?

或类似的东西 :)

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

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

最复杂的JAR地狱问题出现在利用类加载系统的完全复杂性的情况下。 Java程序不需要仅使用单个“平面”类加载器,而是可以由几个(或实际上是不确定数量的)嵌套的协作类加载器组成。 由不同类加载器加载的类可能以复杂的方式进行交互,而开发人员无法完全理解这些类,从而导致无法解释的错误或错误。

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

这个问题可能会有所帮助。

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

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

选择的答案是错误的。 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加载类。

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

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

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

ClassLoader API不对具体实现如何解析类请求施加任何规则。 但是,WEB-INF / lib目录的目的是允许捆绑特定于应用程序的库 。 我怀疑大多数人都希望在jar文件的根目录内搜索lib目录中的jar文件。

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

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

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

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

所以应该首先加载WEB-INF / classes / com / acme / Bunny.class。

你似乎把两种不同的“前”感混为一谈。

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

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