我喜欢服务。我也喜欢模块系统。对我来说不幸的是,在我使用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加载到模块路径上,但是我找不到任何可以执行此操作的方法。所以我在这里,希望这里的人对模块系统有更深入的了解,将告诉我如何做到这一点(或者,如果是这样的话,那是不会的。)
答案 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}}