简体   繁体   English

在Java中实现动态插件

[英]Implementing dynamic plugins in Java

I'd like to implement a dynamic plugin feature in a Java application. 我想在Java应用程序中实现动态插件功能。 Ideally: 理想的情况是:

  • The application would define an interface Plugin with a method like getCapabilities() . 应用程序将使用getCapabilities()等方法定义接口Plugin
  • A plugin would be a JAR pluginX.jar containing a class PluginXImpl implementing Plugin (and maybe some others). 一个插件是一个JAR pluginX.jar含有类PluginXImpl实现Plugin (也许有些人)。
  • The user would put pluginX.jar in a special directory or set a configuration parameter pointing to it. 用户将pluginX.jar放在特殊目录中或设置指向它的配置参数。 The user should not necessarily have to include pluginX.jar in their classpath. 用户不一定要在其类路径中包含pluginX.jar
  • The application would find PluginXImpl (maybe via the JAR manifest, maybe by reflection) and add it to a registry. 该应用程序将找到PluginXImpl (可能通过JAR清单,可能通过反射)并将其添加到注册表。
  • The client could get an instance of PluginXImpl , eg, by invoking a method like getPluginWithCapabilities("X") . 客户端可以获得PluginXImpl的实例,例如,通过调用getPluginWithCapabilities("X") The user should not necessarily have to know the name of the plugin. 用户不一定必须知道插件的名称。

I've got a sense I should be able to do this with peaberry , but I can't make any sense of the documentation. 我有一种感觉,我应该能够用peaberry做到这一点,但我无法理解文档。 I've invested some time in learning Guice, so my preferred answer would not be "use Spring Dynamic Modules ." 我花了一些时间学习Guice,所以我的首选答案不是“使用Spring Dynamic Modules”

Can anybody give me a simple idea of how to go about doing this using Guice/peaberry, OSGi, or just plain Java? 任何人都可以给我一个简单的想法,如何使用Guice / peaberry,OSGi,或只是简单的Java?

This is actually quite easy using plain Java means: 使用普通Java意味着这很简单:

Since you don't want the user to configure the classpath before starting the application, I would first create a URLClassLoader with an array of URLs to the files in your plugin directory. 由于您不希望用户在启动应用程序之前配置类路径,因此我首先要创建一个URLClassLoader,其中包含插件目录中文件的URL数组。 Use File.listFiles to find all plugin jars and then File.toURI().toURL() to get a URL to each file. 使用File.listFiles查找所有插件jar,然后使用File.toURI()。toURL()获取每个文件的URL。 You should pass the system classloader (ClassLoader.getSystemClassLoader()) as a parent to your URLClassLoader. 您应该将系统类加载器(ClassLoader.getSystemClassLoader())作为父类传递给URLClassLoader。

If the plugin jars contain a configuration file in META-INF/services as described in the API documentation for java.util.ServiceLoader, you can now use ServiceLoader.load(Plugin.class, myUrlClassLoader) to obatin a service loader for your Plugin interface and call iterator() on it to get instances of all configured Plugin implementations. 如果插件jar包含META-INF / services中的配置文件,如java.util.ServiceLoader的API文档中所述,您现在可以使用ServiceLoader.load(Plugin.class,myUrlClassLoader)来获取插件接口的服务加载器并在其上调用iterator()以获取所有已配置的插件实现的实例。

You still have to provide your own wrapper around this to filter plugin capabilites, but that shouldn't be too much trouble, I suppose. 你仍然需要提供你自己的包装来过滤插件功能,但我认为这应该不会太麻烦。

OSGI would be fine if you want to replace the plugins during runtime ig for bugfixes in a 24/7 environment. 如果你想在24/7环境中的错误修正的运行时ig期间替换插件,OSGI会没问题。 I played a while with OSGI but it took too much time, because it wasn't a requirement, and you need a plan b if you remove a bundle. 我和OSGI玩了一段时间,但花了太多时间,因为这不是一个要求,如果你删除一个捆绑,你需要一个计划b。

My humble solution then was, providing a properties files with the class names of plugin descriptor classes and let the server call them to register (including quering their capabilities). 我的谦虚解决方案是,提供一个包含插件描述符类的类名的属性文件,让服务器调用它们进行注册(包括查询它们的功能)。

This is obvious suboptimal but I can't wait to read the accepted answer. 这显然不是最理想的,但我迫不及待地想要阅读已接受的答案。

您是否有机会利用服务提供商界面

The best way to implement plug-ins with Guice is with Multibindings . 使用Guice实现插件的最佳方法是使用Multibindings The linked page goes into detail on how to use multibindings to host plugins. 链接页面详细介绍了如何使用多重绑定来托管插件。

Apologize if you know this, but check out the forName method of Class . 如果您知道这一点,请道歉,但请查看ClassforName方法。 It is used at least in JDBC to dynamically load the DBMS-specific driver classes runtime by class name. 它至少在JDBC中用于按类名动态加载特定于DBMS的驱动程序类运行时。

Then I guess it would not be difficult to enumerate all class/jar files in a directory, load each of them, and define an interface for a static method getCapabilities() (or any name you choose) that returns their capabilities/description in whatever terms and format that makes sense for your system. 然后我想枚举目录中的所有类/ jar文件,加载每个文件并定义一个静态方法getCapabilities() (或你选择的任何名称getCapabilities()的接口并不困难,它返回它们的功能/描述。对您的系统有意义的术语和格式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM