JPMS是否支持META-INF/自动模块服务



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

模块系统还扫描META-INF/服务,并使模块提供其中命名的服务。自动模块假定允许使用所有服务。

但是,我有以下情况。我想在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。这是问题的链接。

所以我的问题是:

  1. JPMS支持META-INF/自动模块服务中的服务吗
  2. 如果是,那么如何解释这种行为

编辑总共有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时运行--显示模块分辨率,我会得到以下输出(我用...替换了完整路径(:

...
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模块分辨率,我将获得以下输出:

...
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的所有类,一切正常

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

并且在变量1中不存在这样的线。这里面有问题吗?但是,如果两个模块是自动的,它们就不能自动解决吗?

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

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

最新更新