如何从类装入器获取类路径?

2022-08-31 17:29:26

我正在使用一些第三方代码,当给定一个'-classpath'命令行参数时,它不会设置java.class.path,而只是创建一个类加载器,将命令行上指定类路径上的项目的所有URL添加到类加载器,然后将其设置为上下文类加载器。在我编写的这段代码的插件类中,我得到了这个类装入器的一个实例,并且需要以某种方式使用它来取回底层类路径,这样我就可以在JavaCompiler.getTask(...)的调用中使用它,并动态编译一些其他代码。但是,似乎无论如何都无法从ClassLoader获取ClassPath,并且由于java.class.path未设置,我似乎无法访问应用程序最初调用的基础类路径...有什么想法吗?


答案 1

如果类装入器使用 URL,则它必须是 .您可以访问的是 URL,它定义了它的类路径及其父级 。URLClassloaderClassLoader

要获取 URL,只需执行以下操作:

((URLClassLoader) (Thread.currentThread().getContextClassLoader())).getURLs()

答案 2

今天枚举类路径的最干净方法是使用ClassGraph库(我是作者)。请注意,如果您希望您的代码在今天可移植,那么读取属性或调用的旧答案是可悲的,因为许多运行时环境不再使用,和/或其类装入器不扩展,和/或它们使用一些晦涩的机制来扩展类路径(如jar的清单文件中的属性),和/或您的代码可能作为JDK 9 +中的模块运行(或者您的代码将运行在JDK9+ 中的传统类路径,但传统类路径的标准 JDK 类装入器甚至不再扩展)。java.class.path((URLClassLoader) (Thread.currentThread().getContextClassLoader())).getURLs()java.class.pathURLClassLoaderClass-Path:URLClassLoader

ClassGraph 自动处理大量的类路径规范机制和类装入器实现。对于大多数受支持的类装入器,已经为 ClassGraph 编写了自定义反射代码,以便从类装入器获取类路径(这是必需的,因为 API 没有任何用于获取类路径的标准机制)。您可以为此编写自己的代码,但可能它只会支持而不花费大量精力 - 因此最好只使用ClassGraph,因为这项工作已经为您完成。ClassLoaderURLClassLoader

要获取类路径(以及添加到模块路径的非系统模块化jar),只需调用:

List<URI> classpath = new ClassGraph().getClasspathURIs();

请注意,在Java 9 +中,模块(或jlink'd jars)可能会出现在带有URI的列表中,您无法直接使用它们(除了使用ClassGraph从中读取资源和类,因为ClassGraph还可以使用JPMS API来访问这些资源和类)。您还可以使用 ClassGraph 枚举或扫描类路径中的所有类和/或所有资源(请参阅 ClassGraph wiki)。jrt:

在 Java 9+ 的模块化项目中,您可能还希望获取系统中可见模块的 ModuleReference 对象列表。这些可以通过调用以下内容获得(ModuleRef是一个向后兼容的包装器,因此您可以在JDK 7/8上编译代码,但仍然可以利用JDK 9 +上的模块功能):ModuleReference

List<ModuleRef> modules =
    new ClassGraph()
        .enableSystemPackages() // Optional, to return system modules
        .getModules();

或者,您可以通过调用以下命令来获取传递到命令行(,等)中的实际模块路径,并返回 ModulePathInfo 对象的列表:--module-path--patch-module--add-exports

List<ModulePathInfo> modulePathInfo = new ClassGraph().getModulePathInfo();

推荐