在 Java 中实现动态插件
Posted
技术标签:
【中文标题】在 Java 中实现动态插件【英文标题】:Implementing dynamic plugins in 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 复杂一百倍。有没有好的教程链接? 【参考方案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。我认为这个答案最好地解释了它并提供了另一种选择:***.com/questions/7039467/… @Sergiy:不。我为什么要这样做?【参考方案2】:如果您想在运行时替换插件,OSGI 会很好,例如用于 24/7 环境中的错误修复。我用 OSGI 玩了一段时间,但花了太多时间,因为它不是必需的,如果你删除一个包,你需要一个计划 b。
我当时的简单解决方案是,提供一个带有插件描述符类的类名的属性文件,并让服务器调用它们进行注册(包括查询它们的功能)。
这显然不是最理想的,但我迫不及待地想阅读已接受的答案。
【讨论】:
【参考方案3】:您是否有机会利用Service Provider Interface?
【讨论】:
【参考方案4】:使用 Guice 实现插件的最佳方式是使用 Multibindings。链接页面详细介绍了如何使用多重绑定来托管插件。
【讨论】:
"请注意,此机制在系统运行时无法加载或卸载插件。"在我看来,多重绑定要求插件 JAR 位于类路径上,并且用户在配置文件中指定模块类。也许您可以使用 ClassLoader 动态加载插件目录中的 JAR,但是您必须使用类似服务加载器之类的东西来自动查找模块。【参考方案5】:如果您知道这一点,请道歉,但请查看 Class 的 forName
方法。它至少在 JDBC 中用于通过类名动态加载特定于 DBMS 的驱动程序类运行时。
然后我想枚举一个目录中的所有类/jar文件,加载它们中的每一个,并为返回其功能的静态方法getCapabilities()
(或您选择的任何名称)定义一个接口并不难/以对您的系统有意义的任何术语和格式进行描述。
【讨论】:
@Bandi-T:我在上面添加了一些要求作为回应。我不想使用getPluginInstance("org.example.PluginXImpl")
之类的东西,也不想在类路径中有插件目录。
@Chris Conway:那我很抱歉,这超出了我的能力范围,我在 Java 方面并不是很先进。以上是关于在 Java 中实现动态插件的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Xamarin Forms 中实现 CrossPushNotification 插件?