0

我有一个关于类加载器行为的有趣问题。

问题一: classloader加载jar的顺序是什么?

给出了以下 jars 和包含的类:

a.jar
  +-com/scheffield/foo/A.class

b.jar
  +-com/scheffield/foo/B.class

将加载哪个类?

问题二: classpath中文件的路径和名称是唯一的吗?

给出了以下 jars 和包含的类(真实示例):

spring-beans-3.0.3.RELEASE.jar
  +-META-INF/spring.schemas

spring-aop-3.0.3.RELEASE.jar
  +-META-INF/spring.schemas

我可以告诉你的是,这两个文件都是由 Spring 加载的,否则会发生异常(参见这篇文章)。

我为什么这么问:

我做了一个所谓的大罐子gradle 的食谱条目)。那是一个 jar,其中应用程序类和所有其他依赖项解压缩并打包在大 jar 中。而且我不确定如何处理重复的文件。

4

2 回答 2

2
  1. 类被解析,但是类加载器想要解析它们(这就是拥有类加载器架构的全部意义)。您在实践中处理的大多数类加载器都是java.net.URLClassLoader的变体,它根据目录和 jar 的搜索路径(类路径)加载类(和资源)。搜索路径中的每个位置都被视为类的来源,并按顺序搜索这些位置。

  2. 不,名称不是唯一的。将使用搜索顺序中遇到的第一个。

如果您将罐子组合成一个大罐子,则肯定有可能发生冲突。如果您小心地将它们从有效类路径中的最后一个源合并到第一个源(从而用较早的 jar 覆盖后面的 jar),您将获得大致相同的结果。

我说大概是因为 jar 中的清单包含需要合并的额外处理指令。例如,清单可以包含一个Class-Path 属性,该属性在类路径中包含其他 jar。可以合并 jar,但会丢失指定实际必要类路径的一部分的清单属性。如果您的清单包含密封签名的罐子,那么您可能根本无法在不违反罐子的签名部分的情况下进行此合并。

总之,jars 并不是真正设计为以这种方式合并的。它可以工作,但有很多错误的可能性,其中一些是无法解决的。一个常见的错误原因是合并两个 jar 文件并最终得到多个具有相同路径的条目,这在 zip 文件中是允许的。ant jar 和 zip 任务允许您合并多个源并可能产生此类问题。

实际上,最好将包含许多 jar 和源的 Web 应用程序捆绑到单个 WAR 或 EAR 存档中。这就是它们存在的全部意义所在。

于 2010-12-23T15:01:29.753 回答
0
  1. 这些文件是按照包含 jar 出现在类路径上的顺序加载的。这适用于类。如果您正在加载其他资源(如 spring.schema),您可以使用 classloader.getResource(...) 或 classloader.getResources(...)。第一个返回类路径上的第一个资源,第二个也返回影子资源。
  2. 我认为有效的 zip 存档不包含重复的条目。

问候

于 2010-12-23T13:48:07.323 回答