gpt4 book ai didi

java - 如何安全地访问 Java 9+ 中类路径中所有资源文件的 URL?

转载 作者:IT老高 更新时间:2023-10-28 20:40:26 29 4
gpt4 key购买 nike

我们从 Java 9 的发行说明中了解到那个

The application class loader is no longer an instance of java.net.URLClassLoader (an implementation detail that was never specified in previous releases). Code that assumes that ClassLoader::getSytemClassLoader returns a URLClassLoader object will need to be updated.

这会破坏旧代码,它会按如下方式扫描类路径:

Java <= 8

URL[] ressources = ((URLClassLoader) classLoader).getURLs();

遇到一个

java.lang.ClassCastException: 
java.base/jdk.internal.loader.ClassLoaders$AppClassLoader cannot be cast to
java.base/java.net.URLClassLoader

因此,对于 Java 9+,提出了以下解决方法作为 PR at the Apache Ignite Project ,它在 JVM 运行时选项中按预期工作:--add-opens java.base/jdk.internal.loader=ALL-UNNAMED。然而,正如下面评论中提到的,这个 PR 从未合并到他们的 Master 分支中。

/*
* Java 9 + Bridge to obtain URLs from classpath...
*/
private static URL[] getURLs(ClassLoader classLoader) {
URL[] urls = new URL[0];

try {
//see https://github.com/apache/ignite/pull/2970
Class builtinClazzLoader = Class.forName("jdk.internal.loader.BuiltinClassLoader");

if (builtinClazzLoader != null) {
Field ucpField = builtinClazzLoader.getDeclaredField("ucp");
ucpField.setAccessible(true);

Object ucpObject = ucpField.get(classLoader);
Class clazz = Class.forName("jdk.internal.loader.URLClassPath");

if (clazz != null && ucpObject != null) {
Method getURLs = clazz.getMethod("getURLs");

if (getURLs != null) {
urls = (URL[]) getURLs.invoke(ucpObject);
}
}
}

} catch (NoSuchMethodException | InvocationTargetException | NoSuchFieldException | IllegalAccessException | ClassNotFoundException e) {
logger.error("Could not obtain classpath URLs in Java 9+ - Exception was:");
logger.error(e.getLocalizedMessage(), e);
}
return urls;
}

但是,由于使用 Reflection,这会导致一些严重的头痛。这里。这是一种反模式,受到forbidden-apis maven plugin 的严厉批评。 :

Forbidden method invocation: java.lang.reflect.AccessibleObject#setAccessible(boolean) [Reflection usage to work around access flags fails with SecurityManagers and likely will not work anymore on runtime classes in Java 9]

问题

是否有一种安全的方式来访问类/模块路径中所有资源URLs的列表,可以由给定的类加载器访问,在OpenJDK 9中/10 不使用 sun.misc.* 导入(例如,通过使用 Unsafe)?

更新(与评论有关)

我知道,我可以做到

 String[] pathElements = System.getProperty("java.class.path").split(System.getProperty("path.separator"));

获取classpath中的元素,然后解析到URLs。但是 - 据我所知 - 此属性仅返回应用程序启动时给出的类路径。但是,在容器环境中,这将是应用程序服务器之一,可能还不够,例如然后使用 EAR 包。

更新 2

感谢您的所有评论。我将测试 System.getProperty("java.class.path") 是否适用于我们的目的并更新问题,如果这能满足我们的需求。

然而,似乎 其他项目(可能出于其他原因,例如 Apache TomEE 8) 遭受与 URLClassLoader 相关的同样痛苦——我认为正是出于这个原因这是一个有值(value)的问题。

更新 3

最后,我们确实切换到 classgraph并将我们的代码迁移到这个库以解决我们的用例,以从类路径加载捆绑为 JAR 的 ML 资源。

最佳答案

我想这是 an XY problem .访问类路径上所有资源的 URL 不是 Java 支持的操作,也不是一件好事。正如您在这个问题中已经看到的那样,如果您尝试这样做,您将一直与框架作斗争。将会有一百万个边缘案例会破坏您的解决方案(自定义类加载器、EE 容器等)。

请您详细说明您为什么要这样做?

如果您有某种插件系统并且正在寻找与您的代码接口(interface)的模块,这些模块可能在运行时提供,那么您应该使用 the ServiceLoader API ,即:

A service provider that is packaged as a JAR file for the class path is identified by placing a provider-configuration file in the resource directory META-INF/services. The name of the provider-configuration file is the fully qualified binary name of the service. The provider-configuration file contains a list of fully qualified binary names of service providers, one per line. For example, suppose the service provider com.example.impl.StandardCodecs is packaged in a JAR file for the class path. The JAR file will contain a provider-configuration file named:

META-INF/services/com.example.CodecFactory

that contains the line:

com.example.impl.StandardCodecs # Standard codecs

关于java - 如何安全地访问 Java 9+ 中类路径中所有资源文件的 URL?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49557431/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com