5

我有一个这样的项目:

\---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.是否有可能让它工作并保持主要的未命名模块?

更新 1.3 -添加了相关项目

4

1 回答 1

4

ServiceLoader::load像往常一样工作,但还有其他事情。

[简短回答]

1. 未命名模块读取命名模块命名模块相同,但命名模块不能访问未命名模块中的类型。

2.您正尝试从非模块化 JAR 启动应用程序,因此您必须通过--add-modules com.foo.impl.

请注意,您所需的模块必须在模块图上(例如 add by --module-path)。

[更多细节]

1.有4种不同类型的模块:内置平台模块,命名模块,自动模块, 未命名模块,每个模块都与未命名模块分开命名

在他们编写命名模块时,所有其他模块都像命名模块一样对待:

当然,所有其他模块都有名称,因此我们以后将它们称为命名模块。

未命名的模块读取所有其他模块。[...]

未命名的模块导出其所有包。[...] 但是,这并不意味着命名模块中的代码可以访问未命名模块中的类型。事实上,命名模块甚至不能声明对未命名模块的依赖。[...]

如果在命名模块和未命名模块中都定义了包,则忽略未命名模块中的包。

甚至一个自动模块也确实被命名为

自动模块是隐式定义的命名模块,因为它没有模块声明。

2. 这个答案的第二部分

如果您编译非模块化代码或从非模块化 JAR 启动应用程序,模块系统仍在发挥作用,因为非模块化代码不表达任何依赖关系,它不会从模块路径解析模块。

因此,如果非模块化代码依赖于模块路径上的工件,您需要使用选项手动添加--add-modules它们。不一定全部,只是那些你直接依赖的(模块系统将引入传递依赖) - 或者你可以使用ALL-MODULE-PATH(查看链接的帖子,它更详细地解释了这一点)。

这个@nullpointer 评论会很有用

此外,模块解析仍然需要在启动期间解析 impl。要检查您还可以使用该--show-module-resolution标志。

于 2018-01-21T22:32:55.197 回答