【发布时间】:2019-04-08 14:55:09
【问题描述】:
Here你可以找到以下关于自动模块的内容:
模块系统还会扫描 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
我决定将模块信息添加到log4j-slf4j-impl-2.11.1.jar 并通过provides ... with.. 以JPMS 方式导出服务。问题解决了——我没有得到任何NoClassDefFoundError。这是问题的link。
所以我的问题:
- JPMS 是否支持 META-INF 中的服务/自动模块的服务?
- 如果是,那么如何解释这种行为?
编辑 共有5个模块:
slf4j-api-1.8.0-beta2.jar // name: org.slf4j
log4j-slf4j18-impl-2.11.1.jar // name: org.apache.logging.log4j.slf4j
log4j-core-2.11.1.jar // name: org.apache.logging.log4j.core
log4j-api-2.11.1.jar // name: org.apache.logging.log4j
log4j2-slf4j-jdk11-1.0-SNAPSHOT.jar // name: Log4j2Slf4jJdk11
VARIANT 1 如果我在log4j-slf4j18-impl-2.11.1.jar 有META-INF/services 时运行--show-module-resolution,我会得到以下输出(我用... 替换了完整路径):
...
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 automatic
VARIANT 2 如果我在log4j-slf4j18-impl-2.11.1.jar 有module-info 时运行--show-module-resolution,我会得到以下输出:
...
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
在 VARIANT 1 中,来自 org.apache.logging.log4j.slf4j 的服务无法从 org.apache.logging.log4j.core 加载类 (org.apache.logging.log4j.Logger)。在 VARIANT 2 中,来自org.apache.logging.log4j.slf4j 的服务从org.apache.logging.log4j.core 加载所有类,一切正常。我们在 VARIANT 2 的输出中看到有一行
org.apache.logging.log4j.slf4j requires org.apache.logging.log4j.core
并且在 VARIANT 1 中没有这样的行。问题出在这吗?但是如果两个模块都是自动的,就不能自动解析吗?
【问题讨论】:
-
好吧,看起来 slf4j 不使用ServiceLoader。您可能需要在运行时添加读取边缘。
-
使用
--show-module-resolution运行是查看由于服务绑定而正在解析的模块的好方法。 -
JohannesKuhn SLF4J 1.8 确实使用了 ServiceLoader。 @AlanBateman 谢谢 - 当我使用 --list-modules 测试 Pavel 提供的程序时(请参阅链接的 jira 问题),输出包括 log4j-api jar。当我使用 --show-modules 时,不包括 log4j-api jar。我指定 --modules-path=lib 并且所有 jar 都在该目录中。为什么找不到 log4j-api 模块?我应该注意,没有“真正的”模块声明它们需要 log4j-api,但 log4j-slf4j18-impl 自动模块需要它。
-
@Pavel_K 在 VARIANT1 中,它没有从 Log4j API 中找到 org.apache.logging.log4j.Logger。请注意,您的输出没有显示包含 org.apache.logging.log4j,只有 org.apache.logging.log4j.core。如果您包含 --add-modules=org.apache.logging.log4j 那么您的测试应用程序可以工作。这意味着自动模块不会导致它们可能引用的显式模块被加载。
-
@rgoers 是的,我同意你的看法。问题在于加载模块。所以,我们可以关闭这个问题。
标签: java log4j2 slf4j java-9 java-module