Java JPMS是否支持自动模块的META-INF/services服务?

Java JPMS是否支持自动模块的META-INF/services服务?,java,log4j2,slf4j,java-9,java-module,Java,Log4j2,Slf4j,Java 9,Java Module,关于自动模块,您可以找到以下信息: 该模块系统还扫描META-INF/services,并自动生成 模块提供其中指定的服务。设计了一个自动模块 假设允许使用所有服务 然而,我有以下情况。我想在JPMS中将log4j2与slf4j一起使用。为了做到这一点,log4j-slf4j-impl-2.11.1.jar必须向slf4j-api-1.8.0-beta2.jar提供JPMS服务。log4j的开发者将log4j-slf4j-impl-2.11.1.jar作为自动模块,通过META-INF/serv

关于自动模块,您可以找到以下信息:

该模块系统还扫描META-INF/services,并自动生成 模块提供其中指定的服务。设计了一个自动模块 假设允许使用所有服务

然而,我有以下情况。我想在JPMS中将log4j2与slf4j一起使用。为了做到这一点,
log4j-slf4j-impl-2.11.1.jar
必须向
slf4j-api-1.8.0-beta2.jar
提供JPMS服务。log4j的开发者将
log4j-slf4j-impl-2.11.1.jar
作为自动模块,通过META-INF/services提供服务。但是,它不起作用,至少它给出了以下结果:

Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/logging/log4j/Logger
    at org.apache.logging.log4j.slf4j@2.11.1/org.apache.logging.slf4j.SLF4JServiceProvider.initialize(SLF4JServiceProvider.java:53)
    at org.slf4j/org.slf4j.LoggerFactory.bind(LoggerFactory.java:153)
    at org.slf4j/org.slf4j.LoggerFactory.performInitialization(LoggerFactory.java:141)
    at org.slf4j/org.slf4j.LoggerFactory.getProvider(LoggerFactory.java:419)
    at org.slf4j/org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:405)
    at org.slf4j/org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:354)
    at org.slf4j/org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:380)
    at Log4j2Slf4jJdk11/com.temp.NewMain.<clinit>(NewMain.java:12)
Caused by: java.lang.ClassNotFoundException: org.apache.logging.log4j.Logger
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:582)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
    ... 8 more
变体1如果我运行-
log4j-slf4j18-impl-2.11.1.jar
具有
META-INF/services
时显示模块分辨率,我得到以下输出(我将完整路径替换为
):

变量2如果我运行--当
log4j-slf4j18-impl-2.11.1.jar
具有
模块信息时显示模块分辨率
我得到以下输出:

...
root Log4j2Slf4jJdk11 file:.../log4j2-slf4j-jdk11-1.0-SNAPSHOT.jar
Log4j2Slf4jJdk11 requires org.slf4j file:.../slf4j-api-1.8.0-beta2.jar
jdk.compiler binds org.apache.logging.log4j.core file:.../log4j-core-2.11.1.jar automatic
org.slf4j binds org.apache.logging.log4j.slf4j file:.../log4j-slf4j18-impl-2.11.1.jar
org.apache.logging.log4j.slf4j requires org.slf4j file:.../slf4j-api-1.8.0-beta2.jar
org.apache.logging.log4j.slf4j requires org.apache.logging.log4j.core file:.../log4j-core-2.11.1.jar automatic
org.apache.logging.log4j.slf4j requires org.apache.logging.log4j file:.../log4j-api-2.11.1.jar
org.apache.logging.log4j binds org.apache.logging.log4j.core file:.../log4j-core-2.11.1.jar automatic
在变体1中,
org.apache.logging.log4j.slf4j
中的服务无法从
org.apache.logging.log4j.Logger
加载类(
org.apache.logging.log4j.Logger
)。在变体2中,来自
org.apache.logging.log4j.slf4j
的服务从
org.apache.logging.log4j.core
加载所有类,一切正常。我们在变量2的输出中看到有一条线

org.apache.logging.log4j.slf4j requires org.apache.logging.log4j.core

在变体1中没有这样的行。这里面有问题吗?但是,如果两个模块是自动的,难道它们不能自动解析吗?

SLF4J 1.8需要实现org.SLF4J.spi.SLF4JServiceProvider作为公开服务。在log4j-slf4j18-impl jar中发现。但是,log4jslf4j桥需要log4japi(module org.apache.logging.Log4j)。尽管这是一个显式Java模块,但由于它仅从自动模块引用,因此不会加载它,从而导致ClassNotFoundException


简单的解决方案是在启动应用程序时在命令行中包含--addmodules=org.apache.logging.log4j

嗯,看起来slf4j没有使用。您可能需要在运行时添加读取边缘。使用
--show module resolution
运行可以很好地查看哪些模块由于服务绑定而正在解析。JohannesKuhn SLF4J 1.8确实使用了ServiceLoader@AlanBateman感谢——当我使用——列出模块来测试Pavel提供的程序时(参见链接的jira问题),输出包括log4j api jar。当我使用--show模块时,不包括log4japijar。我指定--modules path=lib,所有JAR都在该目录中。为什么找不到log4japi模块?我应该注意到,没有“真正”的模块声明它们需要log4j api,但是log4j-slf4j18-impl自动模块需要它。@Pavel_K在VARIANT1中没有从log4j api中找到org.apache.logging.log4j.Logger。注意,您的输出没有显示包含org.apache.logging.log4j,只有org.apache.logging.log4j.core。如果您包括--addmodules=org.apache.logging.log4j,那么您的测试应用程序可以工作。这意味着自动模块不会导致加载它们可能引用的显式模块。@rgoers是的,我同意您的看法。问题在于加载模块。所以,我们可以解决这个问题。我做了一个实验,通过改变jlink--module路径上模块的顺序,我成功地消除了--add模块的需要。也许值得一试。
...
root Log4j2Slf4jJdk11 file:.../log4j2-slf4j-jdk11-1.0-SNAPSHOT.jar
Log4j2Slf4jJdk11 requires org.slf4j file:.../slf4j-api-1.8.0-beta2.jar
jdk.compiler binds org.apache.logging.log4j.core file:.../log4j-core-2.11.1.jar automatic
org.slf4j binds org.apache.logging.log4j.slf4j file:.../log4j-slf4j18-impl-2.11.1.jar
org.apache.logging.log4j.slf4j requires org.slf4j file:.../slf4j-api-1.8.0-beta2.jar
org.apache.logging.log4j.slf4j requires org.apache.logging.log4j.core file:.../log4j-core-2.11.1.jar automatic
org.apache.logging.log4j.slf4j requires org.apache.logging.log4j file:.../log4j-api-2.11.1.jar
org.apache.logging.log4j binds org.apache.logging.log4j.core file:.../log4j-core-2.11.1.jar automatic
org.apache.logging.log4j.slf4j requires org.apache.logging.log4j.core