【问题标题】:How to dynamically load class from within a JAR application for use in another JAR?如何从 JAR 应用程序中动态加载类以在另一个 JAR 中使用?
【发布时间】:2018-11-20 04:55:26
【问题描述】:

我有一个 JAR 应用程序 M.jar,它支持动态编写和加载扩展。应用程序要求类实现接口 E 并被称为 NE。

现在,我正在尝试做以下事情,

  1. 编写扩展 API1 并将其加载到 M.
  2. 编写另一个扩展 APIUser,将其加载到 M 并使用 API1。

请参阅下图了解我在这里尝试做的事情。

我知道 M.jar 使用自定义的 ClassLoader,因为它要求任何扩展名都只能命名为 AE。

我尝试了here 中描述的 ServiceProvider、ServiceProviderInterface 方法,但没有奏效。我相信这是因为 API 的类不在 M 的类路径中,因此 APIUser 找不到它。

我想知道,

  1. 如果可以使用 APIUser 的 ClassLoader 加载 API 的类并初始化它以供 APIUser 使用。
  2. M 是否可以阻止/隔离 API 的 ClassLoader 与任何其他扩展?我认为它可以基于this answer
  3. 还有哪些其他方法可以在 APIUser1 或 APIUSer2 中加载 API 类...并且只维护 API 类的一个实例? (即单例)

【问题讨论】:

  • 你知道 OSGi 吗?我认为您的想法与 OSGi 系统架构相似。
  • 为什么ServiceLoader 不适合你?您可以强制执行所有这些检查。
  • @EJP 我不确定为什么 ServiceLoader 不适合我。我假设可能是因为 API 的类不像 M 那样在类路径中?或者至少 APIUser 无法找到这些类/服务。我的 APIUser 迭代器总是返回空实例。而且,我不想使用 URLClassLoader,因为我不希望 APIUser 进行自定义加载。如果有任何帮助,M.jar 的开发人员确认他们为每个扩展使用单独的类加载器。
  • @hiropon 我会调查的。谢谢。

标签: java jar classloader dynamic-class-loaders serviceloader


【解决方案1】:

在对 ClassLoaders 进行了一些研究和研究之后,以下是我对我的问题的了解。

  1. 这无法完成,因为 M.jar 和其他可扩展 Java 程序加载另一个程序的方式是使用 URLClassLoader 作为某个其他 ClassLoader 的子项。这意味着在 ClassLoader 委托层次结构中,API.jar 的 ClassLoader 在层次结构中处于较高位置,而 APIUser.jar 的 ClassLoader 将是同级的。这意味着从 API.jar 加载的类在 APIUser.jar 中不可见。

  2. M 没有明确隔离扩展,但它是将 JAR 加载到应用程序中的自然方式。

  3. 基于对问题 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

【讨论】:

    猜你喜欢
    • 2018-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多