如何从 Java 9 中新创建的层中的模块调用服务?

Pav*_*l_K 5 java java-9 java-module

我有三个模块:模块-a、模块-b、模块-c。Module-a 和 module-b 位于引导层。module-c 层我自己创建。

Module-a 有一个接口com.mod-a.Service,在它的 module-info 中我有:

module module-a {
    exports com.mod-a;
}
Run Code Online (Sandbox Code Playgroud)

Module-c 实现com.mod-a.Service并在其模块信息中我有:

module module-c {
    requires module-a;
    provides com.mod-a.Service with com.mod-c.ServiceImpl;
}
Run Code Online (Sandbox Code Playgroud)

模块-b 使用模块-c 创建新层,并调用模块-c 服务。在它的模块信息中,我有:

module module-b {
    requires module-a;
    requires java.management;
    requires slf4j.api;
    uses com.mod-a.Service;
}
Run Code Online (Sandbox Code Playgroud)

在 module-b 中,我使用 module-c 以这种方式创建新层:

ModuleFinder finder = ModuleFinder.of(moduleCPath);
ModuleLayer parent = ModuleLayer.boot();
Configuration cf = parent.configuration().resolve(finder, ModuleFinder.of(), Set.of("module-c"));
ClassLoader scl = ClassLoader.getSystemClassLoader();
ModuleLayer layer = parent.defineModulesWithOneLoader(cf, scl);
//the following line prints "module-c"
layer.modules().stream().map(Module::getName).forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)

但是,在创建层后,我无法在模块-b 中调用模块-c 的服务。以下代码:

Iterable<Service> it = ServiceLoader.load(Service.class);
System.out.println("LINE 1");
for (Service service : it) {
     System.out.println("Service was called");
     service.doIt();
}
System.out.println("LINE 2");
Run Code Online (Sandbox Code Playgroud)

输出:

LINE 1
LINE 2
Run Code Online (Sandbox Code Playgroud)

我的错误是什么?

Ala*_*man 2

ServiceLoader.load(Class) 使用 TCCL 作为查找服务的服务提供者的起点,而您的示例应使用子层或替代层中定义模块的任何类加载器的类加载器。因此,如果您将示例更改为,ServiceLoader.load(layer, Service.class)那么它应该按您的预期工作。

另外,您已使用resolve服务提供者模块并将其指定为要解析的根模块。这没有什么问题,但另一种选择是使用resolveAndBind而不指定任何根模块。module-b 中的模块uses com.mod-a.Service将确保模块provides com.mod-a.Service将被解析。