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

欢迎!请查看 关于 页面,了解此功能的一些更多信息。

+3
java.classpath

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

这个问题似乎没有直接的答案。

有许多运行 Java 的方法,每种方法可能会得出应用程序类路径的不同定义。历史上,clojure.java.classpath 库采用多种启发式算法来查找和返回 Java 类路径。

当前的方法是针对 Java 9 的一个变通方案,因为在 Java 9 中,默认类加载器不是 URLClassLoader 的实例。现在,当 cider-jack-in 注入 JDK 源路径时(见下文),这给 CIDER 用户带来了问题。

我一直在研究 clojure.java.classpath 的历史,特别是

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

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

我不确定该怎样进行。我对再次更改以解决最近的问题,从而破坏旧用法表示担忧。

请参阅以下讨论

1 答案

+1

为了对此进行扩展,枚举classpath不是那么直截了当的主要原因是Java从未定义一种受支持的枚举方法。

系统类加载器,通常负责加载在java.class.path系统属性上找到的依赖项,仅保证其类型为ClassLoader,这是不可枚举的。

  • 在Java 9之前,可以通过依赖实现细节来枚举系统类加载器:这通常返回一个URLClassLoader,它有一个getURLs方法。但这是一种未记录的行为。

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

  • 直接使用java.class.path系统属性假定了一定的运行时行为,而不是检查实际行为的实际结果。这个假设在很多情况下是成立的,但在其他情况下则会失败。

理想的解决方案是一种可以枚举系统(以及可能平台)类加载器加载的资源的方法,这样就可以枚举整个classpath层次结构。

如果没有这样的方法,对于Java 9+,很可能需要依赖java.class.path属性。如果这样做,次优解决方案应该至少适应以下两种特殊情况

  1. 应用程序可能在一个容器中运行,以及
  2. 动态类加载器可能在运行时添加资源。
我发现这个,它声称是一个通用类路径枚举器。尚未尝试https://github.com/classgraph/classgraph
我看过这个,但也没有时间深入了解。很多可搜索的信息似乎可以追溯到该库的作者。他对Jigsaw支持的笔记有点有帮助:https://github.com/classgraph/classgraph/issues/36。他的灵光一闪似乎还没有让我们得到结果。

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

- 在Java 9及以上的模块系统中,类路径上的所有类都属于未命名的模块,每个类加载器都有自己的未命名的模块。
- 一个模块的资源可以通过ModuleReference对象进行枚举。
- 不幸的是,未命名的模块并不是真正的模块;它们不在模块层或配置中。
- 因此,似乎没有从未命名的模块的Module对象获取ModuleReference的方法。
欢迎来到Clojure问答社区,在这里您可以向Clojure社区成员提问并获得答案。
...