8

我想做一个可以动态加载插件的应用程序,但是我在网上没有找到任何文献。

困难的是:我事先不知道名字。

例如我有一个插件接口:

public interface Plugin {
    public static Plugin newPlugin();
    public void executePlugin(String args[]);
}

这样 jar 文件中的每个实现Plugin的类都在列表中实例化:

Method method = classToLoad.getMethod ("newPlugin");
mylist.add(method.invoke(null);
  1. 第一个问题是,我不能在接口中有静态方法。
  2. 第二个问题是,我不知道如何找到所有实现接口的类

谢谢你的帮助。

4

2 回答 2

27

因此,您似乎希望Plugin在运行时动态发现实现特定接口(例如 )的类。您基本上有两种选择:

  1. 使用像 osgi 这样的组件框架
  2. 使用 Java 的内部发现过程 ( ServiceLoader)

由于 osgi 上有很多很好的教程(也有小的),这里就不详细介绍了。要使用 Java 的内部发现过程,您需要执行以下操作:

  • 将您希望发现的所有“新”类捆绑到一个 jar 文件中
  • jar 文件中创建一个新文件:META-INF/services/package.Plugin您必须在此处使用完整的包限定符
  • Plugin该文件是一个简单的文本文件,包含在该 jar 文件中实现的每个类的完全限定名称
  • 将该 jar 文件放入(可能已经在运行的)应用程序的类路径中
  • 发现服务:

服务发现是这样完成的:

ServiceLoader<Plugin> loader = ServiceLoader.load(Plugin.class)
for (Plugin p : loader) {
    // do something with the plugin
}

这里有更多细节:http: //docs.oracle.com/javase/7/docs/api/java/util/ServiceLoader.html

至于接口中的静态方法:不可能。其语义也会有些奇怪,因为静态方法可以在没有类实例的情况下访问,而接口只是定义方法,没有任何功能。因此,静态将允许调用Interface.doSomething(),而接口没有定义任何功能,这只会导致混乱。

编辑:

添加描述应该在元文件中的内容

于 2012-12-13T23:41:37.303 回答
2

关于你的第一个问题,接口中不能有静态方法,我的建议是简单地使用接口有一个标记并实例化它。

您的插件界面可以简单地是:

public interface Plugin {
  public void executePlugin(String args[]);
}

然后你可以这样做:

if (someClass instanceOf Plugin) {
  mylist.add(someClass.newInstance());
}

这就引出了第二个问题,你将如何获得someClass参考。 没有标准方法可以在您的 classpath中找到所有实现给定接口的类,但是,您可以做的一种方法是扫描您的 classpath 中的 jar,如果给定文件以.class通过它在 jar 内的路径确定它的完整限定名和使用Class.forName()方法来实现类。

在伪代码中是这样的:

for each jar in your classpath {
  for each file in JarFile {
    if (file ends with .class) {
       materialize class using Class.forName
     } 
  }
}

使用该Class实例,您可以检查它是否正在实现您的Plugin接口。

还要记住,如果您需要向插件添加任何上下文,您可以在每个接收上下文对象的插件中创建一个构造函数,而不是使用默认构造函数。在这种情况下,newInstance()您必须通过反射获取带有所需参数的构造函数,而不是使用。

于 2012-12-13T23:48:38.680 回答