ServiceLoader::load 未命名模块与命名模块的交互

Unnamed module interaction with named module by ServiceLoader::load

我有这样一个项目:

\---main
    \---src
        \---com.foo
            \---UnnamedStart.java
\---api
    \---src
        \---com.foo.api
            \---ApiInterface.java
        \---module-info.java
\---impl
    \---src
        \---com.foo.impl
            \---ApiInterfaceImpl.java
        \---module-info.java

UnnamedStart.java 的实现是:

public static void main(String[] args) {
    ServiceLoader<ApiInterface> services = ServiceLoader.load(ApiInterface.class);
    ...
}

注意 main 是未命名的模块。

api/src/module-info.java 是:

module com.foo.api {
     exports com.foo.api;
}

impl/src/module-info.java是:

更新 1.1 - 下面的代码已更新,请参阅评论,添加了 requires

更新 1.2 - 下面的代码已更新,provides A with B 更改为 provides B with A 创建问题时出错,原本是可以的

module com.foo.impl {
     requires com.foo.api; //added (update 1.1)
     provides com.foo.impl.ApiInterface
         with com.foo.api.ApiInterfaceImpl; //vice versa (update 1.2)
}

当我 运行 我在 UnnamedStart.java 中的代码时,我最终在 services 中没有元素。

我也试过在com.foo.api.ApiInterface中创建一个静态方法:

static List<ApiInterface> getInstances() {
    ServiceLoader<ApiInterface> services = ServiceLoader.load(ApiInterface.class);
    List<ApiInterface> list = new ArrayList<>();
    services.iterator().forEachRemaining(list::add);
    return list;
}

并添加到 api/src/module-info.javauses com.foo.api.ApiInterface; 但它给出了相同的结果(无)。

我让它工作的唯一方法是将 main 从未命名模块迁移到命名模块。

1.当未命名模块尝试与命名模块交互时,java 9 如何工作?

2。有没有可能让它工作并保持 main 像未命名的模块?

更新 1.3 - added related project

ServiceLoader::load 照常工作,但还有其他事情。

[简答]

1. 未命名模块读起来和命名模块到[=45=一样]命名模块,但是命名模块无法访问未命名模块.

中的类型

2. 您正在尝试从非模块化 JAR 启动应用程序,因此您必须通过 --add-modules com.foo.impl 明确解析所需的模块。

请注意,您需要的模块必须在 模块图 上(例如按 --module-path 添加)。

[更多详情]

1.有4种不同类型的模块:内置平台模块,命名模块,自动模块,unnamed module 并且它们中的每一个都被命名为 unnamed module

As they wrote 未命名模块 对所有其他模块的处理方式与 已命名模块 相同:

All other modules have names, of course, so we will henceforth refer to those as named modules.

The unnamed module reads every other module. [...]

The unnamed module exports all of its packages. [...] It does not, however, mean that code in a named module can access types in the unnamed module. A named module cannot, in fact, even declare a dependence upon the unnamed module. [...]

If a package is defined in both a named module and the unnamed module then the package in the unnamed module is ignored.

甚至自动模块确实也是named:

An automatic module is a named module that is defined implicitly, since it does not have a module declaration.

2.

If you compile non-modular code or launch an application from a non-modular JAR, the module system is still in play and because non-modular code does not express any dependencies, it will not resolve modules from the module path.

So if non-modular code depends on artifacts on the module path, you need to add them manually with the --add-modules option. Not necessarily all of them, just those that you directly depend on (the module system will pull in transitive dependencies) - or you can use ALL-MODULE-PATH (check the linked post, it explains this in more detail).

这条@nullpointer 评论会有用

Also, the module resolution still needed the impl to be resolved during the startup. To check which you could also flag.