将Java serviceloader与jdk8一起用于> = java9

问题描述 投票:0回答:1

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

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

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

所以,我将java serivceloader api与Java 8或9一起使用时没有问题。

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

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

java java-module serviceloader
1个回答
1
投票

在JDK9及更高版本中,所有jar都是有效的“模块”。如果它们not具有模块定义(通过创建名为module-info.java的文件并在其中放置模块声明来创建),则其名称为“未命名的模块@whatever”,它将导出其所有软件包,并可以访问任何其他模块导出的任何内容(在模块方面:它“读取”所有内容)。意思是,如果all您的类路径依赖项是这样的未命名模块,它们都将导出所有内容,并且都将读取所有内容,因此它们都可以从其他任何人访问标有public的任何内容–这就是在JDK8中的工作方式,因此,为什么它们都兼容。

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

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

该错误表示'未命名模块@ 3754a4bf'[3]无法'访问'[2]的“服务类型” [1]。让我们将其分解成碎片:

[1]服务加载器通过定义“服务提供者”实现的接口来工作,然后使用服务加载器的类以该接口的一堆实例结束;每个代表一个实现。这是public中的Foo

[2]“可访问”是模块的代名词:需要此代码的代码没有显式“读取”它,或者有此代码的代码没有导出它。

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

[全部考虑,这意味着:您在错误的假设下进行操作:无论jar包含您的服务接口(我在说ServiceLoader.load(Foo.class),是NOT一个未命名的模块,或者可能不是不公开。请注意,如果它是非公共类(即Foo)内的公共接口,则可能仍算作“不够公共”。

如果它是一个命名模块(这意味着:它具有/* package private */ class Example { public interface MyServiceInterface {} }文件),则导出服务接口所在的包。有关如何设置它的信息,请参见任何拼图(java模块系统的名称)教程。 。如果不是,请确保它是公共接口或抽象类,并且如果在其他类型中,请确保它们也是公共的。如果不是这种情况,请检查您的类路径; javac坚信这是其中之一。

© www.soinside.com 2019 - 2024. All rights reserved.