2012-12-13 57 views
5

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

困难的是:我不知道名字提前。

比如我有一个插件接口:

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

这样所有的类实现插件 jar文件列表中的实例:

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

感谢您的帮助所有类。

+0

是否有配置文件指定哪些插件为您的问题加载合适的解决方案? – Mac

+0

嗨,Mac在我的情况下,我想避免有一个配置文件,只是如果一个文件夹中存在一个jar试图加载它。谢谢。 – FloFu

回答

20

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

  1. 使用像OSGi的组件架构
  2. 使用Java的内部发现过程(ServiceLoader

既然有OSGi的很多很好的教程(也小的) ,我不会在这里详细说明。使用Java内部的发现过程,你需要做到以下几点:

  • 捆绑所有你想要的“新”类发现到一个JAR文件
  • 创建一个新的文件 jar文件:META-INF/services/package.Plugin您必须使用此
  • 全包限制这个文件是一个简单的文本文件,包含每类在JAR文件执行Plugin
  • 将是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()而接口没有定义任何功能,这只会导致混淆。

编辑:

添加描述应该是在元文件

+0

我不认为有人对你表示欢迎SirRichie,但你非常欢迎这个社区。投了所有四个答案:) –

+0

谢谢:)现在我只需要学习如何正确地格式化代码... – SirRichie

+0

通常,您只需在第一行用4个空格缩进,然后跳过一行。然后,在另一空行之后,从0位置开始,为其余的普通文本开始。您可以使用内嵌代码的字符环绕代码。 –

2

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

你的插件接口可以简单地是:

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

然后你就可以这样做:

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

这导致了第二个问题,你将如何得到someClass参考。 没有标准的方式找到你的classpath实现一个给定接口所有类,虽然,你可以做一个方法是扫描的罐子在classpath中,如果给定的文件,.class结束确定它的全限定名通过它是jar中的路径,并使用Class.forName()方法来实现Class。

在伪代码是这样的:

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

随着Class来说,如果它的实现你的Plugin界面,您可以检查。

另外请记住,如果你需要添加任何上下文到你的插件,你可以在每个接收你的上下文对象的插件创建一个构造函数,而不是默认的构造函数。在这种情况下,而不是使用newInstance()你将不得不通过反射得到你想要的构造函数。