URLClassLoader.getResources(“”)(空资源名称)没有给出jar的根

时间:2014-02-17 18:48:38

标签: java url jar classloader

考虑使用URLClassLoader的集合参数化的URL,它是扩展目录和jar文件的混合。例如:

URL[] urls = new URL[] {
    new URL("file:/D:/work/temp/jars/spring-security-core-3.2.0.RELEASE.jar"),
    new URL("file:/D:/work/temp/jars/spring-security-config-3.2.0.RELEASE.jar"),
    ...
    new URL("file:/D:/work/temp/domain/bin/"),
    new URL("file:/D:/work/temp/web/bin/"),
    ...
}
URLClassLoader cl = new URLClassLoader(urls);

类加载器正确处理getResources()"org/my/package/conf.properties"之类的包内某处资源的请求。通过正确处理我的意思是类加载器成功找到目录和jar中的所有匹配项。

getResources("")中传递的特殊空字符串名称应该生成所有可用根的URL(在目录和jar中)。然而,ClassLoader中存在已知的限制,这导致仅返回对应于目录的根。所有根罐子都被丢弃了。

使用classloader.getURLs[]代替classloader.getResources("")对我不起作用,因为我有一个相互依赖的URLClassLoader的复杂图表,因此结果将完全不同。此外,我的类加载器将由使用getResources("")调用的第三方类路径扫描工具使用,以便设置内部搜索库。这样就无法找到位于罐子里的资源。

我目前有一个工作修复方法,我从URLClassLoader扩展并通过强制root用于jars以及URL s返回集合中的目录的句子来手动处理带有空字符串的请求。 / p>

但我的问题是:

  • 此限制的概念/技术原因是什么(未返回到jar的路径)?

  • 通过手动修复,我是否违反了任何重要合同?

  • 有没有很好的方法来获得理想的行为?

感谢您的任何想法!

1 个答案:

答案 0 :(得分:2)

此限制的概念/技术原因是什么(不返回 jar 的路径)?

ClassLoader.getResources("") 的行为未指定。

URLClassPath$Loader 中的文件系统加载资源的实现完全基于 URL。它通过将资源名称添加到目录的基本 URL 来构造一个新的文件 URL 并在指向现有资源时返回 URL。 对空资源名称没有特殊处理。 这是否是通缉行为没有记录。

URLClassPath$JarLoader 中 JAR 文件的实现适用于 JAR 文件的索引。要获得 JAR 文件的相同行为,实现需要对空资源名称进行特殊处理,即它需要首先检查空资源名称并返回 JAR 文件的文件 URL,而不是在索引中搜索。该实现没有对 empy 资源名称进行特殊处理。这是否是通缉行为再次没有记录。

由于 API 规范没有指定行为 空资源名称两个实现都是有效的。

有些人可能会争辩说,暴露根目录是一个安全问题,尤其是在沙箱中运行时。其他人可能会争辩说 getResources() 应该为空资源返回 null,因为实际上不存在名为“”的资源。

在任何情况下,URLClassLoader 的当前行为都会导致 Class.getResource() 中出现意外行为。当使用默认包中的类的空字符串调用此方法时,它会在从文件系统加载类时返回该类的根目录。这违反了方法的约定。有关详细信息,请参见例如这个开放的 Java 错误:https://bugs.openjdk.java.net/browse/JDK-8202687

通过手动修复此问题,我是否违反了任何重要合同?

只要你只覆盖 findResource() 方法 的 ClassLoader,调用 super 方法,然后添加额外的 您不应违反任何合同的 JAR 文件的网址。

但请注意,已经有一些实现对 URLClassLoaders 进行了特殊处理。例如 Spring 的 PathMatchingResourcePatternResolver 对作为 URLClassLoader 实例的类加载器进行了特殊处理 (here),它为 JAR 添加了额外的 URL。

有什么好的方法可以得到想要的行为吗?

没有很好的方法来获得所需的行为,因为每个解决方案都基于未指定的行为,理论上可能会随着每个新的 JRE 版本而改变。

随着 Java 9 中多版本 JAR 文件的引入,行为已经改变:

对于包含 Java 8 类和 Java 9 类的多版本 JAR 文件 ClassLoader.getResource("") 现在在 JRE 版本 > 8 内执行时返回 JAR 文件的 URL。对于 JRE 8,它仍然不返回相同 JAR 文件的 URL。有了它,空资源字符串的返回 URL 现在甚至取决于 JRE 版本,resp。 JAR 文件的类型。

存在获取 JAR 文件 URL 的变通方法。 PathMachintResourcePatternResolver 例如从 java.class.path 系统属性加载 JAR 文件名(对于系统类加载器)并通过调用 URLClassLoader.getURLs()(对于 URLClassLoader )。但同样,这些只是基于未指定行为的解决方法。

理想情况下,类路径上的搜索仅在 java 包的上下文中执行。像 Spring (boot) 这样的框架只在 java 包的上下文中对类路径执行搜索。这避免了依赖类加载器的未指定行为,也避免在不相关的第三方库的 JAR 文件中进行搜索。 因此,我建议尽可能在 java 包的上下文中搜索类路径,而不是使用空资源名称搜索资源。