简体   繁体   English

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

[英]How to call a service from module in a new created layer in Java 9?

I have three modules: module-a, module-b, module-c. 我有三个模块:module-a,module-b,module-c。 Module-a and module-b are in boot layer. 模块-a和模块-b在引导层中。 Layer for module-c I create myself. 模块-c的层我自己创建。

Module-a has one interface com.mod-a.Service and in its module-info I have: Module-a有一个接口com.mod-a.Service ,在我的模块信息中我有:

module module-a {
    exports com.mod-a;
}

Module-c implements com.mod-a.Service and in its module-info I have: Module-c实现了com.mod-a.Service ,在我的模块信息中我有:

module module-c {
    requires module-a;
    provides com.mod-a.Service with com.mod-c.ServiceImpl;
}

Module-b creates new layer with module-c, and calls module-c service. Module-b使用module-c创建新层,并调用module-c服务。 In its module-info I have: 在我的模块信息中,我有:

module module-b {
    requires module-a;
    requires java.management;
    requires slf4j.api;
    uses com.mod-a.Service;
}

In module-b I create new layer with module-c this way: 在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);

However, after creating layer I can't in module-b call Service of module-c. 但是,在创建图层后我无法在module-b中调用module-c的Service。 The following code: 以下代码:

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");

outputs: 输出:

LINE 1
LINE 2

What is my mistake? 我的错是什么?

ServiceLoader.load(Class) uses the TCCL as the starting point to locate service providers for the service whereas your example should use the child layer or alternative the class loader of any class loader defining modules in the layer. ServiceLoader.load(Class)使用TCCL作为定位服务的服务提供者的起点,而您的示例应该使用子层或替代任何类加载器的类加载器来定义层中的模块。 So if you change the example to ServiceLoader.load(layer, Service.class) then it should work as you expect. 因此,如果您将示例更改为ServiceLoader.load(layer, Service.class)那么它应该按预期工作。

Separately, you've used resolve and specified the service provider module as the root module to resolve. 另外,您已使用resolve并将服务提供者模块指定为要解析的根模块。 Nothing wrong with that but an alternative would have been to use resolveAndBind and not specify any root modules. 没有错,但替代方案是使用resolveAndBind并且不指定任何根模块。 The uses com.mod-a.Service in module-b will ensure that modules that provides com.mod-a.Service will be resolved. 模块uses com.mod-a.Serviceuses com.mod-a.Service将确保解析provides com.mod-a.Service模块。

The root cause of your issue is that the 你的问题的根本原因是

ServiceLoader.load(Service.class) 

which is an alternate of 这是一个替代

ServiceLoader.load(Service.class, Thread.currentThread().getContextClassLoader())

doesn't end up finding any service provider for the Service . 没有最终找到的任何服务提供商Service

One way in which I was able to fix that was to open the package of the service provider to the module which owns the service, as : 我能够解决的一种方法是将服务提供者的包打开到拥有该服务的模块,如下所示:

module module-c {
    requires module-a;
    provides com.mod-a.Service with com.mod-c.ServiceImpl;
    opens com.mod-c to module-a;
}

Also, would suggest going through the ServiceLoader on how to deploy service providers as module and on the classpath . 此外,建议通过ServiceLoader了解如何将服务提供程序部署为模块类路径

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM