我正在努力使我的Java应用程序模块化,以便客户端将拥有核心基础模块,但是他/她将能够在它们出现时添加其他功能/插件,或者随着她的需求扩展。就像NetBeans这样的IDE一样。
我计划在客户端pc中有一个名为modules / plugins的子目录,其中任何插件应用程序将作为.jar文件包含在内。当用户启动应用程序时,主模块将在最终项目中包含这些其他插件,因此,例如,Stage将具有来自主模块和插件模块的按钮{{3 }}
我精通scene,使用视图执行此操作。借用这个,我可以有一个HBox,例如在启动应用程序时从不同插件中填充Buttons的主模块上。
如何让core_base_module.jar调用下面的plugins目录中的所有插件。换句话说,如何让一个.jar
文件调用另一个.jar
文件?
示例目录结构:
main dir/---core_base_module.jar
/---plugins ---/chat.jar
/videoplayer.jar
/like.jar
/unlike.jar
/etc.jar
/etc_etc.jar
答案 0 :(得分:4)
您可以通过以下方式手动执行此操作:
虽然您可以自己完成所有操作,但使用Service Loader API可能会更容易。此API是Java的一部分,是为此目的而创建的。这是spring用来加载可以处理spring XML配置文件中的不同XML标记的插件。例如,查看spring-web.jar!/META-INF/services
然后你会希望你的启动脚本将所有JAR添加到主类路径中,如下所示:
java -cp plugins/* -jar app.jar
或者如果你没有lauch脚本,你可以在java中做同样的事情,但创建一个URLClassLoader传递你想要的所有jar文件,然后在这个新的类加载器中调用你的主类。 / p>
更多信息:
答案 1 :(得分:1)
如果您真的想要创建专业级应用程序,@ David Roussel建议的ServiceLoader API是您的选择。
如果你喜欢更轻量级的东西,你可以手工,,你可以只使用一个API包,其中只包含你在应用程序中包含的抽象类接口,以及一个包含实际的实现包您作为单独的jar提供的类。由于您无法通过new
通过接口创建对象,因此您必须使用工厂模式和反射。您还应该使用Class.forName("package.to.class")
来测试程序开头的实施存在。
示例假设接口Foo
可选地由FooImpl
实现,其构造函数采用工厂可能的字符串参数:
public class FooFactory {
public static final String CLASSNAME = "...FooImpl";
public static Foo createFoo(String key) {
try {
Class<?> fooclazz = Class.forName(CLASSNAME);
Foo foo = (Foo) fooclazz.getConstructor(String.class).newInstance(key);
return foo;
}
catch (Exception e) {
// eventually process some exceptions
}
return null;
}
}
您最初使用以下命令设置全局布尔值hasFoo
(主类的静态成员):
try {
Class.forName(FooFactory.CLASSNAME);
hasOpt = true;
}
catch (Exception e) {
hasOpt = false;
}
你可以选择使用它:
if (MainClass.hasOpt) {
Foo foo = FooFactory.createFoo("bar");
// do something with foo
}
else {
// warning message : Option not present
}
使用此方法,只需在类路径中添加实现jar并重新启动应用程序即可使用它。