【问题标题】:Why ClassLoader returns a path with extraneous second exclamation point为什么 ClassLoader 返回带有多余的第二个感叹号的路径
【发布时间】:2018-04-27 17:59:02
【问题描述】:

我正在尝试获取ClassLoader 中的资源。代码的简化版本如下所示:

String ePath = "rewrite/common/RenameFunctor.groovy"
String fPath = ThClType.class.getClassLoader().getResource(ePath);

我作为 fPath 得到的响应是 jar:file:/Users/myName/warPath/warName.war!/WEB-INF/classes!/rewrite/common/RenameFunctor.groovy。我们想要的资源的实际路径正是如此,除了没有第二个感叹号。 (与warName.war不同,classes只是一个普通目录。)

有谁知道可能是什么导致了额外的感叹号和/或可以采取什么措施来解决它?这是更新一些我没有编写的非常旧代码的过程的一部分,因此如果可以对 ClassLoader 行为进行深奥的定制,那么在这种情况下可能已经完成了。如果它可能的,那么我不知道如何检查,并希望有任何见解。

【问题讨论】:

  • 不确定实现细节,但是类路径中资源的“路径”是/rewrite/common/RenameFunctor.groovy!-分隔的部分似乎标识了类中条目的路径路径:首先是 WAR /Users/myName/warPath/warName.war,然后是 WAR /WEB-INF/classes。它实际上是添加到类路径中的最后一个条目的内容。
  • @MarkRotteveel 对……但/WEB-INF/classes 实际上并不是一场战争。这就是问题所在。路径应该jar:file:/Users/myName/warPath/warName.war!/WEB-INF/classes/rewrite/common/RenameFunctor.groovy
  • 你错过了我的观点。 WAR 本身和WEB-INF/classes 都不在类路径上(而WEB-INF/classes 是类路径的一部分)。但是,WEB-INF/classescontent 位于类路径中。例如使用SomeClass.class.getResourceAsStrean("/rewrite/common/RenameFunctor.groovy") 将能够加载该文件的内容,但SomeClass.class.getResourceAsStrean("/WEB-INF/classes/rewrite/common/RenameFunctor.groovy") 不会,因为/WEB-INF/classes 不在类路径上。看起来 WAR 类加载器通过! 分隔路径来表明这一点
  • @MarkRotteveel 好的。我想我明白你在说什么,虽然我不知道在这种情况下如何确认。不幸的是,我正在尝试使用它来填充 GroovyCodeSource,因此“使用流”的答案并不像人们希望的那样有用。我可以为它拼凑一个阅读器,但我认为我无法管理代码库。不过,看起来这至少是部分答案,而且很有帮助,我会邀请您将其写成一个。它确实回答了原始问题中的两个问题之一。

标签: java classloader war


【解决方案1】:

警告:这个答案是对机制的部分假设和猜测,它可能不是 100% 正确,但我认为它已经足够接近了。据我所知,实际的 WAR 类加载会因 servlet 容器或应用程序服务器而异,所以这个答案可能并不适用于所有这些。

如果你看

jar:file:/Users/myName/warPath/warName.war!/WEB-INF/classes!/rewrite/common/RenameFunctor.groovy

你可以把它分成以下几个部分:

  1. file:/Users/myName/warPath/warName.war
  2. /WEB-INF/classes
  3. /rewrite/common/RenameFunctor.groovy

类路径上的实际资源是最后一个,/rewrite/common/RenameFunctor.groovy,其他部分是war类加载器用于查找包含该资源的类路径部分的坐标:首先是战争文件本身,file:/Users/myName/warPath/warName.war,然后是战争中的路径,/WEB-INF/classes

该理论建立在JarURLConnection 的文档之上,该文档指出:

到 Java ARchive (JAR) 文件或 JAR 中的条目的 URL 连接 文件。

JAR URL 的语法是:

jar:<url>!/{entry}  

例如:

jar:http://www.foo.com/bar/baz.jar!/COM/foo/Quux.class

Jar URL 应该用于引用 JAR 文件或 JAR 中的条目 文件。上面的示例是一个引用 JAR 条目的 JAR URL。如果 条目名称被省略,URL 指的是整个 JAR 文件: jar:http://www.foo.com/bar/baz.jar!/

所以对于普通的 jar,URL 的第一部分标识 jar 文件本身,第二部分标识 jar 中的资源。

从技术上讲,war 文件是 jar 文件,但与 jar 文件相反,war 文件本身不是类路径的一部分。相反,它包含添加到类路径中的元素。例如,WEB-INF/lib 中的 jar 文件以及 WEB-INF/classes 中的类和其他文件。

! 分隔的部分随后定义了 war 类加载器为定位特定资源所采取的步骤,在本例中为 /rewrite/common/RenameFunctor.groovy

【讨论】:

    猜你喜欢
    • 2012-03-20
    • 1970-01-01
    • 1970-01-01
    • 2012-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-22
    • 2018-11-14
    相关资源
    最近更新 更多