使用 java serviceloader 构建与 jdk8 使用 >= java9

Pet*_*ter 4 java serviceloader java-module

我有两个罐子。一种提供服务接口和服务加载类,另一种提供该服务的实现。

在 jdk8 中运行时效果很好,但service type not accessible to unnamed module @3754a4bf在 jdk9 或更高版本上运行时出现错误。

我将这两个 jar 迁移到了一个模块基础 jar,并且在 >= jdk9 上运行时效果很好,但由于类文件版本错误,在 jdk8 上运行失败。

所以,我在 java 8 或 9 中使用 java serivceloader api 没有问题。

我知道https://blog.codefx.org/tools/multi-release-jars-multiple-java-versions/,但我想避免使构建过程变得更加复杂。构建已经涉及类重定位和其他内容。

我的问题:有没有办法使用 java serviceloading api 使用在 jdk8 和 >=jdk9 上运行的相同 jar ?

rzw*_*oot 6

在 JDK9 及更高版本中,所有 jar 实际上都是“模块”。如果它们没有模块定义(通过创建一个名为文件module-info.java并在其中放入模块声明来创建),则其名称为“未命名模块@whatever”,它会导出其所有包,并且可以访问任何其他模块导出的任何内容(用模块的话说:它“读取”所有内容)。意思是,如果您所有的类路径依赖项都是这样的未命名模块,那么它们都会导出所有内容,并且都会读取所有内容,因此它们都可以访问public其他人标记的任何内容 \xe2\x80\x93 这就是它在 JDK8 中的工作方式,因此,为什么它是全部兼容。

\n\n

需要明确的是:在 JDK9 中,模块(jar)A 中的代码要访问模块(jar)B 中的方法、类或字段,那么除了通常的访问修饰符(关键字public)之外,B 还需要“导出”那个包,A需要读取那个模块,否则就不起作用。如果您没有明确地为任何一方编写模块信息文件,那么您会得到默认行为,即“导出所有内容”和“读取所有内容”,这让我们回到了 JDK8 场景:必须标记该内容public,然后你就可以访问它了。

\n\n

我实际上不建议您创建该模块信息文件;这是一大步,只有在熟悉了模块系统后才应该采取这一步骤。

\n\n

该错误意味着“未命名模块@3754a4bf”[3]无法“访问”[2]“服务类型”[1]。让我们把它分成几部分:

\n\n

[1] 服务加载器通过定义“服务提供者”实现的接口来工作,然后使用服务加载器的类最终得到该接口的一堆实例;每个代表一个实现。这是FooServiceLoader.load(Foo.class).

\n\n

[2]“可访问”是模块的意思:要么需要它的代码没有显式地“读取”它,要么拥有它的代码没有导出它。

\n\n

[3] 'unnamed module@3754abf' 是尝试访问它的模块的名称。

\n\n

将所有这些放在一起,这意味着:您在错误的假设下操作:无论包含您的服务接口(Foo我正在谈论的)的 jar 是什么,都不是未命名的模块,或者可能不是公开的。请注意,如果它是非公共类中的公共接口(即:)/* package private */ class Example { public interface MyServiceInterface {} },则可能仍然被视为“不够公共”。

\n\n

如果它是一个命名模块(这意味着:它有一个module-info.java文件),则导出服务接口所在的包。有关如何设置它的信息,请参阅任何 jigsaw(java 模块系统的名称)教程。如果不是,请确保它是公共接口或抽象类,如果它位于其他类型中,请确保它们也是公共的。如果不是这种情况,请检查您的类路径;javac 相当坚定地认为这两种情况之一就是这种情况。

\n