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.class.path属性对Java 9+来说可能是必要的。如果是这样,次优解决方案应至少考虑到两种特定情况:

  1. 应用程序可能在一个容器中运行,
  2. 动态类加载器可能会在运行时添加资源。
我发现这个,它声称是一个通用的classpath枚举器。还没有试用过 https://github.com/classgraph/classgraph
我看到了这一点,但也没有时间深入研究。可搜索信息的大部分似乎是那个库作者的痕迹。他关于Jigsaw支持的笔记有些帮助:[链接](https://github.com/classgraph/classgraph/issues/36)。但他的灵感时刻似乎也没有帮助我们解决这个问题。

我很快就尝试了使用模块系统,但这并不顺利。一些笔记

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