我正在尝试获取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 行为进行深奥的定制,那么在这种情况下可能已经完成了。如果它可能,那么我不知道如何检查,并且希望有任何见解。
最佳答案
警告:这个答案是对机制的部分假设和猜测,它可能不是 100% 正确,但我认为它已经足够接近了。据我所知,实际的 WAR 类加载会因 servlet 容器或应用程序服务器而异,因此这个答案可能并不适用于所有这些。
如果你看
jar:file:/Users/myName/warPath/warName.war!/WEB-INF/classes!/rewrite/common/RenameFunctor.groovy
您可以将其分为以下部分:
文件:/Users/myName/warPath/warName.war
/WEB-INF/classes
/rewrite/common/RenameFunctor.groovy
类路径上的实际资源是最后一个,/rewrite/common/RenameFunctor.groovy
,其他部分是war类加载器用来查找的部分的坐标包含该资源的类路径:首先是 war 文件本身的位置,file:/Users/myName/warPath/warName.war
,然后是 war 内的路径,/WEB -INF/类
。
该理论建立在 JarURLConnection
的文档之上,其中指出:
A URL Connection to a Java ARchive (JAR) file or an entry in a JAR file.
The syntax of a JAR URL is:
jar:<url>!/{entry}
for example:
jar:http://www.foo.com/bar/baz.jar!/COM/foo/Quux.class
Jar URLs should be used to refer to a JAR file or entries in a JAR file. The example above is a JAR URL which refers to a JAR entry. If the entry name is omitted, the URL refers to the whole JAR file:
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
。
关于java - 为什么 ClassLoader 返回带有第二个无关感叹号的路径,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50067888/