我有一个 JAR 应用程序 M.jar,它支持动态编写和加载扩展。应用程序要求类实现接口(interface) E 并称为 NE。
现在,以下是我正在尝试做的事情,
- 编写扩展 API1 并将其加载到 M。
- 编写另一个扩展 APIUser,将其加载到 M 并使用 API1。
请参阅下图了解我在这里尝试执行的操作。
我知道 M.jar 使用自定义类加载器,因为它要求任何扩展名仅命名为 AE。
我尝试了 ServiceProvider、ServiceProviderInterface 方法,如所述 here但这没有用。我相信这是因为 API 的类不在 M 的类路径中,因此 APIUser 找不到它。
我想知道
- 是否可以使用 APIUser 的 ClassLoader 来加载 API 的类并初始化它以便在 APIUser 中使用。
- M 是否可以阻止/隔离 API 的类加载器与任何其他扩展?我认为它可以基于 this answer .
- 还有什么其他方法可以在 APIUser1 或 APIUSer2 中加载 API 类...并仅维护 API 类的一个实例? (即单例)
最佳答案
经过对类加载器的一些研究和学习,以下是我对我的问题的了解。
这是无法完成的,因为 M.jar 和其他可扩展 Java 程序加载另一个程序的方式是使用 URLClassLoader 作为其他某个 ClassLoader 的子级。这意味着在 ClassLoader 委托(delegate)层次结构中,API.jar 的 ClassLoader 位于层次结构中的较高位置,而 APIUser.jar 的 ClassLoader 将是同级。这意味着从 API.jar 加载的类在 APIUser.jar 中不可见。
M 没有明确隔离扩展,但它是将 JAR 加载到应用程序中的自然方式。
根据问题 1 的答案,我现在要做的方法是使用 hackish在运行时将 JAR 添加到 SystemClassLoader 的类路径,然后通过使用 SystemClassLoader 加载它从其他/任何扩展引用它的方法。这是因为 SystemClassLoader 从任何扩展中都是可见的。
注释:我还假设 ServiceLoader 执行此操作的方式也可以工作。但我自己没有尝试过。
引用文献:
https://zeroturnaround.com/rebellabs/rebel-labs-tutorial-do-you-really-get-classloaders/
https://docs.oracle.com/javase/8/docs/api/java/lang/ClassLoader.html
关于java - 如何从 JAR 应用程序中动态加载类以在另一个 JAR 中使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50789278/