如何在运行时扩展模块路径

时间:2019-01-17 02:42:46

标签: java java-9 java-module module-info

我喜欢服务。我也喜欢模块系统。对我来说不幸的是,在我使用Java 9之前,我习惯于在运行时通过URLClassLoader从jar中加载服务提供者,这是类似的事情(为简洁起见,我将使用Java 10的var):< / p>

var url = new File("myjar.jar").toURI().toURL();
var cl = new URLClassLoader(new URL[] {url}, getClass().getClassLoader());
var services = ServiceLoader.load(MyService.class, cl);
for (var service : services) {
  ...
}

即使在Java 9和更高版本中,此方法也可以正常工作,但是它将jar加载到类路径上,这意味着它使用旧的META-INF\services方法来查找服务提供者。我宁愿使用module-info方法,但这需要将jar加载到模块路径上,但是我找不到任何可以执行此操作的方法。所以我在这里,希望这里的人对模块系统有更深入的了解,将告诉我如何做到这一点(或者,如果是这样的话,那是不会的。)

2 个答案:

答案 0 :(得分:4)

我可以组装的最小的工作示例是

var path = Path.of("myjar.jar");
var cl = new URLClassLoader(new URL[]{path.toUri().toURL()});
var mf = ModuleFinder.of(path);
var cfg = Configuration.resolve(mf, List.of(ModuleLayer.boot().configuration()), mf, Set.of());
var ml = ModuleLayer.defineModulesWithOneLoader(cfg, List.of(ModuleLayer.boot()), cl).layer();
var services = ServiceLoader.load(ml, MyService.class);
services.forEach(System.out::println);

假设myjar.jar是声明要提供MyService实现的模块化jar。

答案 1 :(得分:0)

原来我使用了错误的命令行选项(我不知道我不应该对模块化jar使用Configuration.resolve)。使用正确的命令,@ Holger的答案行得通,除了传递给var path = Path.of("myjar.jar"); var cl = new URLClassLoader(new URL[]{path.toUri().toURL()}); var mf = ModuleFinder.of(path); var cfg = Configuration.resolve(mf, List.of(ModuleLayer.boot().configuration()), mf, mf.findAll().stream().map(module -> module.descriptor().name()).collect(Collectors.toSet())); var ml = ModuleLayer.defineModulesWithOneLoader(cfg, List.of(ModuleLayer.boot()), cl).layer(); var services = ServiceLoader.load(ml, MyService.class); services.forEach(System.out::println); 的集合需要包含要加载的模块的所有名称,这很容易修复:

{{1}}