解决这个问题最简单的方法是使用ServiceLoader(文档here)。它包含在 Java 中,使用起来相当简单:
- 在运行时加载 Jar 文件
- 检测实现特定接口的类(例如:
your.package.YourService)。
- 从这些类中实例化对象。
Here 是一篇很好的文章,描述了如何做到这一点(注意:您应该使用带有URLCLassLoader 的第二个建议;不动态扩展类路径)。另外,不要忘记在 Jar 的 META-INF 目录中声明您的服务:
如果com.example.impl.StandardCodecs 是
CodecSet service 那么它的jar文件也包含一个名为
的文件
META-INF/services/com.example.CodecSet
这个文件包含一行:
com.example.impl.StandardCodecs # Standard codecs
通过选择这种方法,您的核心程序自然会处理您的插件,因此将能够轻松地与它们进行通信。为了确保双向通信(即插件调用您的核心程序),我建议创建一个您的核心程序将实现的接口,并将该接口传递给您的插件。
插件接口:
public interface Plugin {
public void doPluginStuff(Caller caller);
}
核心程序Caller接口:
public interface Caller {
public void sendBackResults(Object results);
}
插件实现(在单独的 Jar 文件中):
public class AParticularPlugin implements Plugin {
public void doPluginStuff(Caller caller){
caller.sendBackResults("Hello world");
}
}
核心计划:
public class CoreProgram implements Caller {
public void callPlugin(URL[] urlToJarFiles){
URLClassLoader ucl = new URLClassLoader(urlToJarFiles);
ServiceLoader<Plugin> sl = ServiceLoader.load(Plugin.class, ucl);
Iterator<Plugin> plugins = sl.iterator();
while (plugins.hasNext())
plugins.next().doPluginStuff(this);
}
public void sendBackResults(Object results){
System.out.println(results.toString());
}
}