在 Java 中实现动态插件

2022-09-02 21:47:55

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

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

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

任何人都可以给我一个简单的想法,如何使用Guice / peaberry,OSGi或普通的Java来做到这一点?


答案 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() 以获取所有已配置插件实现的实例。

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


答案 2

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

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

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


推荐