2024 Clojure状态调查!中分享您的想法。

欢迎!请参阅关于页面了解有关此操作的更多信息。

+3
java.classpath

"我的应用程序的类路径是什么?"

结果证明,对这个问题的回答并不简单。

运行Java的方法有很多,每种方法可能导致应用程序类路径的不同定义。clojure.java.classpath库历来使用各种启发式算法来查找和返回Java类路径。

当前的方法是针对Java 9的问题的一种权宜之计,其中默认类加载器不是一个URLClassLoader的实例。这现在给CIDER用户在使用cider-jack-in注入JDK源路径(如下所示)时带来了问题。

我正在查看clojure.java.classpath的历史,特别是

似乎没有一种方法可以在所有情况下都给出正确的结果。

  • 使用系统属性java.class.path在应用程序容器环境中会产生错误的结果(CLASSPATH-1)。
  • 从URLClassLoaders获取类路径在Java 9+中不起作用(CLASSPATH-8)。
  • 合并结果将为CIDER和tools.namespace等工具提供更全面的覆盖,但可能会为容器中的应用程序返回错误的结果。

我不确定如何进行下去。我对再次改变以满足最新问题感到担忧,从而破坏旧的处理方式。

另请参阅以下讨论

1 答案

+1

编辑

稍作扩展,列举classpath的主要原因是Java从未定义一种受支持的列举方式。

系统类加载器通常加载在系统属性java.class.path上找到的依赖项,但有保证它的类型是ClassLoader,而这不能被列举。

  • 直到Java 9,可以通过依赖实现细节来列举系统类加载器:它会可靠地返回一个URLClassLoader,它有一个getURLs方法。然而,这是一种未记录的行为。

  • 从Java 9开始,系统类加载器实现改为一个不可枚举的内部类。

  • 直接使用系统属性java.class.path隐含了某种运行时行为,而不是检查实际行为的结果。这个假设在许多情况下是成立的,但在其他情况下可能失败。

理想解决方案是一个能在Java 9+上工作,并且能列举系统类加载器和(可能)平台类加载器加载的资源的方式,以便整个classpath层次结构都可以被列举。

如果没有这个解决方案,对于Java 9+,可能需要依赖于java.class.path属性。如果是这样的话,最佳替代方案应该至少能够解决以下两个特定情况

  1. 应用程序可能在一个容器中运行,
  2. 动态类加载器可能在运行时添加资源。
我找到了这个宣称是一般用途的classpath列举器。尚未尝试https://github.com/classgraph/classgraph
我确实见过,但也没什么时间深入研究。大量可搜索的信息似乎都可以追溯到那个库的作者。他为Jigsaw支持的笔记有些帮助:[访问链接](https://github.com/classgraph/classgraph/issues/36)。不过,他的灵感时刻似乎并没有帮我们到达目的地。

我尝试了一下使用模块系统,但并不顺畅。以下是一些注意事项

- 在Java 9+的模块系统中,类路径上的所有类都属于无名称模块,每个类加载器都有自己的。
- 模块的资源可以通过ModuleReference对象进行枚举。
- 不幸的是,无名称模块并不是真正的模块;它们不在模块层或配置中。
- 因此,似乎没有从无名称模块的Module对象中获取ModuleReference的方法。
...