【问题标题】:Implementing dynamic plugins in Java在 Java 中实现动态插件
【发布时间】:2011-01-07 11:16:35
【问题描述】:

我想在 Java 应用程序中实现动态插件功能。理想情况下:

  • 应用程序将使用getCapabilities() 之类的方法定义一个接口Plugin
  • 插件将是一个 JAR pluginX.jar,其中包含一个实现 Plugin 的类 PluginXImpl(可能还有其他一些)。
  • 用户将pluginX.jar 放在一个特殊的目录中或设置一个指向它的配置参数。用户不一定必须在其类路径中包含 pluginX.jar
  • 应用程序会找到 PluginXImpl(可能通过 JAR 清单,也可能通过反射)并将其添加到注册表中。
  • 客户端可以获得PluginXImpl的实例,例如,通过调用类似getPluginWithCapabilities("X")的方法。用户不一定必须知道插件的名称。

我有一种感觉,我应该能够使用 peaberry 做到这一点,但我无法理解文档。我花了一些时间学习 Guice,所以我的首选答案不是“使用Spring Dynamic Modules”。

谁能给我一个简单的想法,告诉我如何使用 Guice/peaberry、OSGi 或纯 Java 来做这件事?

【问题讨论】:

  • Peaberry 和 Spring DM 都是 OSGi 之上的层。 OSGi 似乎(从概念上)做你想做的事,但它会以“OSGi 方式”来做,不会映射到你的确切过程,所以建议谷歌搜索一些 OSGi 教程。
  • OSGi 看起来比 peaberry 复杂一百倍。有没有好的教程链接?

标签: java plugins osgi guice peaberry


【解决方案1】:

这实际上很容易使用纯 Java 方法:

由于您不希望用户在启动应用程序之前配置类路径,我将首先创建一个 URLClassLoader,其中包含指向插件目录中文件的 URL 数组。使用 File.listFiles 查找所有插件 jar,然后使用 File.toURI().toURL() 获取每个文件的 URL。您应该将系统类加载器 (ClassLoader.getSystemClassLoader()) 作为父级传递给您的 URLClassLoader。

如果插件 jar 包含 META-INF/services 中的配置文件,如 java.util.ServiceLoader 的 API 文档中所述,您现在可以使用 ServiceLoader.load(Plugin.class, myUrlClassLoader) 获取服务加载器您的插件接口并在其上调用 iterator() 以获取所有已配置插件实现的实例。

您仍然需要为此提供自己的包装器来过滤插件功能,但我想这应该不会太麻烦。

【讨论】:

  • 你能解释得更详细一点吗?
  • 除非你有更详细的问题。
  • @jarnbjo:这完全有效!谢谢!我仍然有兴趣看到 peaberry 或 OSGi 解决方案...
  • 在 SO 周围的各个地方,我看到人们不鼓励使用 ServiceLoaders。我认为这个答案最好地解释了它并提供了另一种选择:stackoverflow.com/questions/7039467/…
  • @Sergiy:不。我为什么要这样做?
【解决方案2】:

如果您想在运行时替换插件,OSGI 会很好,例如用于 24/7 环境中的错误修复。我用 OSGI 玩了一段时间,但花了太多时间,因为它不是必需的,如果你删除一个包,你需要一个计划 b。

我当时的简单解决方案是,提供一个带有插件描述符类的类名的属性文件,并让服务器调用它们进行注册(包括查询它们的功能)。

这显然不是最理想的,但我迫不及待地想阅读已接受的答案。

【讨论】:

    【解决方案3】:

    您是否有机会利用Service Provider Interface

    【讨论】:

      【解决方案4】:

      使用 Guice 实现插件的最佳方式是使用 Multibindings。链接页面详细介绍了如何使用多重绑定来托管插件。

      【讨论】:

      • "请注意,此机制在系统运行时无法加载或卸载插件。"在我看来,多重绑定要求插件 JAR 位于类路径上,并且用户在配置文件中指定模块类。也许您可以使用 ClassLoader 动态加载插件目录中的 JAR,但是您必须使用类似服务加载器之类的东西来自动查找模块。
      【解决方案5】:

      如果您知道这一点,请道歉,但请查看 ClassforName 方法。它至少在 JDBC 中用于通过类名动态加载特定于 DBMS 的驱动程序类运行时。

      然后我想枚举一个目录中的所有类/jar文件,加载它们中的每一个,并为返回其功能的静态方法getCapabilities()(或您选择的任何名称)定义一个接口并不难/以对您的系统有意义的任何术语和格式进行描述。

      【讨论】:

      • @Bandi-T:我在上面添加了一些要求作为回应。我不想使用getPluginInstance("org.example.PluginXImpl") 之类的东西,也不想在类路径中有插件目录。
      • @Chris Conway:那我很抱歉,这超出了我的能力范围,我在 Java 方面并不是很先进。
      猜你喜欢
      • 1970-01-01
      • 2020-05-29
      • 2011-09-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-20
      • 2012-07-14
      • 2016-12-17
      相关资源
      最近更新 更多