简而言之,该实施是 Sun 内部工作的一部分,不能通过公共方式实现。getURLs()
只会返回传入的 URL。有一个更长的答案,但只适合大胆的人。
使用调试器单步执行 Oracle JVM 8 让我了解了与 OpenJDK6 几乎相同的结构,您可以看到它加载类路径的位置here.
基本上,类加载器会保留一堆尚未解析到内存中的 URL。当被要求加载一个类时,它会将 URL 从堆栈中弹出,将它们作为类文件或 jar 文件加载,如果它们是 jar 文件,它会读取清单并将类路径条目推送到堆栈上。每次处理文件时,它都会添加“加载器”,将该文件加载到加载器映射中(如果没有其他情况,以确保它不会多次处理同一文件)。
如果您确实有动力这样做(不推荐),您可以访问此地图:
Field secretField = URLClassLoader.class.getDeclaredField("ucp");
secretField.setAccessible(true);
Object ucp = secretField.get(loader);
secretField = ucp.getClass().getDeclaredField("lmap");
secretField.setAccessible(true);
return secretField.get(ucp);
在虚拟设置上运行它,我有 dummy-plugin.jar 引用 external.jar (在 dummy-plugin.jar 的清单中),我得到以下信息:
1) 创建类加载器之后(加载任何类之前):
urlClassLoader.getURLs()=[file:.../dummy-plugin.jar]
getSecretUrlsStack=[file:.../dummy-plugin.jar]
getSecretLmapField={}
2) 从 dummy-plugin.jar 加载类后:
urlClassLoader.getURLs()=[file:.../dummy-plugin.jar]
getSecretUrlsStack=[file:.../external.jar]
getSecretLmapField={file:.../dummy-plugin.jar=sun.misc.URLClassPath$JarLoader@736e9adb}
3)从external.jar加载类后:
urlClassLoader.getURLs()=[file:.../dummy-plugin.jar]
getSecretUrlsStack=[]
getSecretLmapField={file:.../dummy-plugin.jar=sun.misc.URLClassPath$JarLoader@736e9adb, file:.../external.jar=sun.misc.URLClassPath$JarLoader@2d8e6db6}
奇怪的是,这似乎与URLClassLoader 的 JDK:
默认情况下加载的类仅授予以下权限
访问创建 URLClassLoader 时指定的 URL。