Java 空路径约定,尤其是在 ClassLoader.getResources 中使用的约定
Java empty path convention, especially that used in ClassLoader.getResources
今天,我很惊讶(可能是因为缺乏经验)发现您可以将空路径(字面意思是空字符串)传递给 ClassLoader.getResources
,这实际上很有用,即
ClassLoader.getSystemClassLoader().getResources("")
。根据一些测试,returns 我的应用程序 .class
文件所在的一两个目录(并且不包括第 3 方包的目录)。 (用法示例:Get all of the Classes in the Classpath。)
大概是因为JavaSystem ClassLoader是加载我自己的应用程序classes(c.f.http://www.oracle.com/technetwork/articles/javase/classloaders-140370.html)的三个ClassLoader之一,所以URL 返回指向我的应用程序 class 文件的目录也就不足为奇了。
但是空字符串为什么以及如何实现这一点?我没有找到它的记录。这是更常见的 Java 约定的空路径派生词吗?它肯定不是 Linux - 你不能 cd
进入 bash 中的空路径。如果有人能帮助我理解这一点,我将不胜感激。
在另一个笔记中,我注意到 getResources(".")
实现了同样的事情。
评论讨论补充
public class myTest {
public static void main(String[] args) throws Exception {
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
URL[] urls = ((URLClassLoader) classLoader).getURLs();
for (int n = 0; n < urls.length; n++)
System.out.println(urls[n]); //lists external.jar
Enumeration<URL> roots = classLoader.getResources(".");
while (roots.hasMoreElements()) {
URL url = roots.nextElement();
System.out.println("getResources: " + url); //does not list external.jar
}
}
}
要执行的命令:java -cp ".:external.jar" myTest
当给定资源名称“”或“.”时,为什么 getResources(String)
调用匹配所有 class 目录路径条目?
我只能推测。对于它的价值,我认为这是特定 ClassLoader
的实现细节。顺便说一句“”和“。尽管如此,从文件系统用户的角度来看,资源名称的处理还是有些直观。
...如何?
默认的OpenJDK应用程序ClassLoader
(也称为系统ClassLoader
),sun.misc.Launcher$AppClassLoader
,是一个URLClassLoader
具有 URL 搜索路径的后代包含 "java.class.path" 系统 属性 的值。它的 getResources
(还有 getResource
)方法最终委托给 sun.misc.URLClassPath$FileLoader.getResource(String, boolean)
,后者执行以下操作:
url = new URL(getBaseURL(), ParseUtil.encodePath(name, false));
...
file = new File(dir, name.replace('/', File.separatorChar)); // dir is the equivalent of getBaseURL()'s path component
...
if (file.exists()) {
return new sun.misc.Resource() {
...
public URL getURL() { return url; } // eventually returned by the ClassLoader
}
}
撇开所有 URL 解析,资源名称本质上被视为相对文件系统路径,并且 "absolutized" 针对加载程序的搜索路径条目。因此 name
参数为“”或“.”。匹配搜索路径条目本身。换句话说,所有顶级 classpath 条目都被匹配和 returned,就好像它们都位于同一根目录下一样。请注意,这不适用于 JAR class 路径条目,它们由 sun.misc.URLClassPath$JarLoader
.
处理
为什么这些 getResources
调用也不匹配 JAR class 路径条目?为什么 class 路径条目包含在由 URLClassLoader.getURLs()
编辑的数组 return 中?
API-明智...
这是两种不相关的方法,每种方法都有不同的用途。有时他们 "just happen" 会产生相同或相似的输出——但是他们的规范在任何地方都没有暗示任何形式的行为相互一致。
getResources
,根据URLClassLoader
对术语"resource"的具体定义,指定为return个文件、目录或JAR条目下面 它的搜索路径。 return 搜索路径条目本身,当它们代表目录时,它也发生在其规范中未解决的事实,因此应将其视为实现细节(也可能是轻微的规范违规)和不可信赖。同样,它没有 return JAR 搜索路径条目这一事实虽然与前者不一致,但并不违反其规范。
getURLs
,另一方面,return是实例化时提供的确切1搜索路径条目。
实施方面...
与 sun.misc.URLClassPath$FileLoader
不同,如前所述,它根据每个搜索路径条目的文件系统路径解析资源名称,sun.misc.URLClassPath$JarLoader
尝试通过 JarFile.getEntry(name)
进行直接匹配,对于“”和大多数可能是“.”,条目名称,显然失败了。但是,即使两个 URLClassPath.Loader
都以相同的方式解释资源名称,事情也不会按预期进行,因为嵌入式 JAR 文件系统不支持根目录的概念。
那么我应该如何检索所有 class 路径条目?
要独立于系统 ClassLoader
执行此操作,请使用类似
的内容
String[] classPathEntries = System.getProperty("java.class.path").split(File.pathSeparator);
,最好在 main
方法的早期,在任何第三方代码有机会修改 属性.
之前
ClassLoader.getSystemClassLoader()
有一个 return 类型的 java.lang.ClassLoader
。我们如何(确定地)知道 returned 实例是 sun.misc.Launcher$AppClassLoader
?
我们真的不知道。系统 class 加载程序依赖于实现并且可以替换。一如既往,我们所能做的就是测试,例如
try {
ClassLoader sysCl = ClassLoader.getSystemClassLoader();
// not using single-arg Class.forName, since it would use the ClassLoader of this class,
// which, in the worst-case scenario of being a non-delegating loader, could attempt to load AppClassLoader itself
if (Class.forName("sun.misc.Launcher$AppClassLoader", false, sysCl).isAssignableFrom(sysCl.getClass())) {
// default implementation, _most likely_ a URLClassLoader subclass
}
else {
// System ClassLoader overridden, or not on OpenJDK
}
}
catch (ReflectiveOperationException roe) {
// most likely not on OpenJDK
}
,并采取相应行动。
1 这可能并不总是成立,例如,当搜索路径条目 "overlap"(一个是另一个的父级)或安全限制适用时;有关详细信息,请参阅 sun.misc.URLClassPath
的来源。
今天,我很惊讶(可能是因为缺乏经验)发现您可以将空路径(字面意思是空字符串)传递给 ClassLoader.getResources
,这实际上很有用,即
ClassLoader.getSystemClassLoader().getResources("")
。根据一些测试,returns 我的应用程序 .class
文件所在的一两个目录(并且不包括第 3 方包的目录)。 (用法示例:Get all of the Classes in the Classpath。)
大概是因为JavaSystem ClassLoader是加载我自己的应用程序classes(c.f.http://www.oracle.com/technetwork/articles/javase/classloaders-140370.html)的三个ClassLoader之一,所以URL 返回指向我的应用程序 class 文件的目录也就不足为奇了。
但是空字符串为什么以及如何实现这一点?我没有找到它的记录。这是更常见的 Java 约定的空路径派生词吗?它肯定不是 Linux - 你不能 cd
进入 bash 中的空路径。如果有人能帮助我理解这一点,我将不胜感激。
在另一个笔记中,我注意到 getResources(".")
实现了同样的事情。
评论讨论补充
public class myTest {
public static void main(String[] args) throws Exception {
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
URL[] urls = ((URLClassLoader) classLoader).getURLs();
for (int n = 0; n < urls.length; n++)
System.out.println(urls[n]); //lists external.jar
Enumeration<URL> roots = classLoader.getResources(".");
while (roots.hasMoreElements()) {
URL url = roots.nextElement();
System.out.println("getResources: " + url); //does not list external.jar
}
}
}
要执行的命令:java -cp ".:external.jar" myTest
当给定资源名称“”或“.”时,为什么 getResources(String)
调用匹配所有 class 目录路径条目?
我只能推测。对于它的价值,我认为这是特定 ClassLoader
的实现细节。顺便说一句“”和“。尽管如此,从文件系统用户的角度来看,资源名称的处理还是有些直观。
...如何?
默认的OpenJDK应用程序ClassLoader
(也称为系统ClassLoader
),sun.misc.Launcher$AppClassLoader
,是一个URLClassLoader
具有 URL 搜索路径的后代包含 "java.class.path" 系统 属性 的值。它的 getResources
(还有 getResource
)方法最终委托给 sun.misc.URLClassPath$FileLoader.getResource(String, boolean)
,后者执行以下操作:
url = new URL(getBaseURL(), ParseUtil.encodePath(name, false));
...
file = new File(dir, name.replace('/', File.separatorChar)); // dir is the equivalent of getBaseURL()'s path component
...
if (file.exists()) {
return new sun.misc.Resource() {
...
public URL getURL() { return url; } // eventually returned by the ClassLoader
}
}
撇开所有 URL 解析,资源名称本质上被视为相对文件系统路径,并且 "absolutized" 针对加载程序的搜索路径条目。因此 name
参数为“”或“.”。匹配搜索路径条目本身。换句话说,所有顶级 classpath 条目都被匹配和 returned,就好像它们都位于同一根目录下一样。请注意,这不适用于 JAR class 路径条目,它们由 sun.misc.URLClassPath$JarLoader
.
为什么这些 getResources
调用也不匹配 JAR class 路径条目?为什么 class 路径条目包含在由 URLClassLoader.getURLs()
编辑的数组 return 中?
API-明智...
这是两种不相关的方法,每种方法都有不同的用途。有时他们 "just happen" 会产生相同或相似的输出——但是他们的规范在任何地方都没有暗示任何形式的行为相互一致。
getResources
,根据URLClassLoader
对术语"resource"的具体定义,指定为return个文件、目录或JAR条目下面 它的搜索路径。 return 搜索路径条目本身,当它们代表目录时,它也发生在其规范中未解决的事实,因此应将其视为实现细节(也可能是轻微的规范违规)和不可信赖。同样,它没有 return JAR 搜索路径条目这一事实虽然与前者不一致,但并不违反其规范。
getURLs
,另一方面,return是实例化时提供的确切1搜索路径条目。
实施方面...
与 sun.misc.URLClassPath$FileLoader
不同,如前所述,它根据每个搜索路径条目的文件系统路径解析资源名称,sun.misc.URLClassPath$JarLoader
尝试通过 JarFile.getEntry(name)
进行直接匹配,对于“”和大多数可能是“.”,条目名称,显然失败了。但是,即使两个 URLClassPath.Loader
都以相同的方式解释资源名称,事情也不会按预期进行,因为嵌入式 JAR 文件系统不支持根目录的概念。
那么我应该如何检索所有 class 路径条目?
要独立于系统 ClassLoader
执行此操作,请使用类似
String[] classPathEntries = System.getProperty("java.class.path").split(File.pathSeparator);
,最好在 main
方法的早期,在任何第三方代码有机会修改 属性.
ClassLoader.getSystemClassLoader()
有一个 return 类型的 java.lang.ClassLoader
。我们如何(确定地)知道 returned 实例是 sun.misc.Launcher$AppClassLoader
?
我们真的不知道。系统 class 加载程序依赖于实现并且可以替换。一如既往,我们所能做的就是测试,例如
try {
ClassLoader sysCl = ClassLoader.getSystemClassLoader();
// not using single-arg Class.forName, since it would use the ClassLoader of this class,
// which, in the worst-case scenario of being a non-delegating loader, could attempt to load AppClassLoader itself
if (Class.forName("sun.misc.Launcher$AppClassLoader", false, sysCl).isAssignableFrom(sysCl.getClass())) {
// default implementation, _most likely_ a URLClassLoader subclass
}
else {
// System ClassLoader overridden, or not on OpenJDK
}
}
catch (ReflectiveOperationException roe) {
// most likely not on OpenJDK
}
,并采取相应行动。
1 这可能并不总是成立,例如,当搜索路径条目 "overlap"(一个是另一个的父级)或安全限制适用时;有关详细信息,请参阅
sun.misc.URLClassPath
的来源。