如何在Java 9/10中安全地访问类路径中所有资源文件的URL? [英] How to safely access the URLs of all resource files in the classpath in Java 9/10?

查看:210
本文介绍了如何在Java 9/10中安全地访问类路径中所有资源文件的URL?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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


应用程序类加载器不再是java.net.URLClassLoader的实例(从未指定过的实现细节)在以前的版本中)。假定ClassLoader :: getSytemClassLoader返回URLClassLoader对象的代码需要更新。

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.

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

This breaks old code, which scans the classpath as follows:

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 + ,建议将以下解决方法作为 Apache Ignite Project的PR ,根据JVM运行时选项中的调整,按预期工作: - add-opens java.base / jdk.internal.loader = ALL-UNNAMED 。但是,正如下面的评论所述,这个PR从未合并到他们的主分支。

So for Java 9+ the following workaround was proposed as a PR at the Apache Ignite Project, which works as intended given adjustments in the JVM runtime options: --add-opens java.base/jdk.internal.loader=ALL-UNNAMED. However, as mentioned in the comments below, this PR was never merged into their Master branch.

/*
 * 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;
}

然而,由于使用了反思。这是一种反模式,并受到 forbidden-apis maven plugin :

However, this causes some severe headache due to the use of Reflection here. This is kind of an anti-pattern and is strictly criticized by the forbidden-apis maven plugin:


禁止方法调用:java.lang.reflect.AccessibleObject #setAccessible(boolean)[解决访问标志的反射用法失败, SecurityManagers并且可能在Java 9中不再适用于运行时类]

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]



问题



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

Question

Is there a safe way to access the list of all resource URLs in the class- / module path, which can be accessed by the given classloader, in OpenJDK 9/10 without using sun.misc.* imports (e.g. by using Unsafe)?

更新(与评论相关)

我知道,我可以做

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

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

to obtain the elements in the classpath and then parse them to URLs. However - as far as I know - this property only returns the classpath given at the time of the application launch. However, in a container environment this will be the one of the application server and might not be sufficient, e.g. then using EAR bundles.

更新2

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

Thank your for all your comments. I will test, if System.getProperty("java.class.path") will work for our purposes and update the question, if this fullfills our needs.

然而,似乎其他项目(可能出于其他原因,例如Apache TomEE 8)遭受与<$ c相关的痛苦$ c> URLClassLoader - 因此,我认为这是一个有价值的问题。

However, it seems that other projects (maybe for other reasons, e.g Apache TomEE 8) suffer the same pain related to the URLClassLoader- for this reason, I think it is a valueable question.

推荐答案

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

I think this is an XY problem. Accessing the URLs of all resources on the classpath is not a supported operation in Java and is not a good thing to try to do. As you have already seen in this question, you will be fighting against the framework all the way if you try to do this. There will be a million edge cases that will break your solution (custom classloaders, EE containers, etc. etc.).

请您扩展您想要做的原因这个?

Please could you expand on why you want to do this?

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

If you have some kind of plugin system and are looking for modules that interface with your code which may have been provided at runtime, then you should use the ServiceLoader API, i.e.:


通过将提供者配置文件放在资源目录中来识别打包为类路径的JAR文件的服务提供者 META -INF /服务。 provider-configuration文件的名称是服务的完全限定二进制名称。 provider-configuration文件包含服务提供者的完全限定二进制名称列表,每行一个。
例如,假设服务提供者 com.example.impl.StandardCodecs 打包在类路径的JAR文件中。 JAR文件将包含名为的提供者配置文件:

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

包含以下行:

com.example.impl.StandardCodecs # Standard codecs


这篇关于如何在Java 9/10中安全地访问类路径中所有资源文件的URL?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆