我想创建一个可以动态加载插件的应用程序,但我没有在互联网上找到任何文献。
困难之处在于:我事先并不知道这个名字。
例如,我有插件界面:
public interface Plugin {
public static Plugin newPlugin();
public void executePlugin(String args[]);
}
这样,在jar文件中实现插件的每个类都在列表中实例化:
Method method = classToLoad.getMethod ("newPlugin");
mylist.add(method.invoke(null);
感谢您的帮助。
答案 0 :(得分:23)
因此,您似乎希望在运行时动态发现实现特定接口(例如,Plugin
)的类。你基本上有两种选择:
ServiceLoader
)由于有许多关于osgi(也是小的)的好教程,我不会在这里详述。要使用Java的内部发现过程,您需要执行以下操作:
META-INF/services/package.Plugin
您必须在此处使用完整的包限定符Plugin
的每个类的完全限定名称服务发现是这样完成的:
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()
而接口不定义任何功能,这只会导致混淆。
编辑:
添加了描述元文件中的内容
答案 1 :(得分:2)
关于你的第一个问题,在接口中无法使用静态方法,我的建议是简单地使用接口有一个标记并实例化它。
你的插件界面可以简单地是:
public interface Plugin {
public void executePlugin(String args[]);
}
然后你可以这样做:
if (someClass instanceOf Plugin) {
mylist.add(someClass.newInstance());
}
这导致了第二个问题,您将如何获得someClass
参考。
没有标准的方法来查找在类路径中实现给定接口的所有类,但是,如果给定的文件,您可以执行的方法是扫描类路径中的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()
,而是必须通过反射获得您想要的参数的构造函数。