Java 17下无法加载org.jboss.logmanager.LogManager的解决方案咨询
问题背景
Docker中运行WildFly时,Java 8环境可正常加载org.jboss.logmanager.LogManager,但切换到Java 17后,原-Xbootclasspath/a参数失效,出现ClassNotFoundException和NoClassDefFoundError,同时需要保证JMX及JMX Exporter正常工作。
核心原因
Java 9+引入模块化系统后,-Xbootclasspath/a参数被大幅限制,无法再将第三方日志管理器直接添加到启动类路径;同时JMX Exporter的agent在LogManager初始化前就触发了日志操作,导致默认JDK日志管理器先被加载,进而无法切换到JBoss LogManager。
解决方案
1. 替换废弃参数,使用模块化兼容配置
删除jboss-config中的-Xbootclasspath/a配置,替换为Java 17支持的模块化参数,确保JBoss LogManager能访问JDK内部日志API:
--add-modules=java.logging --add-exports=java.logging/sun.util.logging=ALL-UNNAMED --add-exports=java.base/java.util.logging=ALL-UNNAMED --patch-module=java.logging=/opt/jboss/wildfly/modules/system/layers/base/org/jboss/logmanager/main/jboss-logmanager-1.5.2.Final.jar:/opt/jboss/wildfly/modules/system/layers/base/org/jboss/logging/main/jboss-logging-3.1.4.GA.jar
2. 调整参数顺序,优先初始化LogManager
将LogManager相关配置放在-javaagent参数之前,避免JMX Exporter提前触发日志初始化:
-Djava.util.logging.manager=org.jboss.logmanager.LogManager \ -Djava.util.logging.ConsoleHandler.level=ALL \ -Djboss.modules.system.pkgs=org.jboss.byteman,org.jboss.logmanager \ -javaagent:/opt/jmx_exporter/jmx_exporter.jar=1090:/opt/jmx_exporter/jmx_config.yaml \
3. 升级JBoss LogManager到Java 17兼容版本(推荐)
WildFly 28默认的jboss-logmanager版本已兼容Java 17,若当前使用的jboss-logmanager-1.5.2.Final.jar过旧,直接替换为WildFly 28自带的新版本(路径:$JBOSS_HOME/modules/system/layers/base/org/jboss/logmanager/main/,版本通常为2.0+)。
4. 优化Dockerfile中的WildFly配置
修改standalone.conf的配置方式,直接追加正确的JAVA_OPTS,避免依赖外部文件:
RUN echo "JAVA_OPTS=\"\$JAVA_OPTS --add-modules=java.logging --add-exports=java.logging/sun.util.logging=ALL-UNNAMED --add-exports=java.base/java.util.logging=ALL-UNNAMED --patch-module=java.logging=/opt/jboss/wildfly/modules/system/layers/base/org/jboss/logmanager/main/jboss-logmanager-1.5.2.Final.jar:/opt/jboss/wildfly/modules/system/layers/base/org/jboss/logging/main/jboss-logging-3.1.4.GA.jar -Djava.util.logging.manager=org.jboss.logmanager.LogManager -Djava.util.logging.ConsoleHandler.level=ALL -Djboss.modules.system.pkgs=org.jboss.byteman,org.jboss.logmanager\"" >> $JBOSS_HOME/bin/standalone.conf
原始配置及错误日志
DockerFile
ENV JAVA_HOME=/usr/lib/jvm/java ENV WILDFLY_VERSION=28.0.1.Final ENV WILDFLY_SHA1=8702fb7ba8d1249bf058e2223f662e5176b39d0d ENV JBOSS_HOME=/opt/jboss/wildfly ENV JMX_EXPORTER_VERSION=0.16.1 RUN cd $HOME && \ curl -OL https://github.com/wildfly/wildfly/releases/download/$WILDFLY_VERSION/wildfly-$WILDFLY_VERSION.tar.gz && \ echo "$WILDFLY_SHA1 wildfly-$WILDFLY_VERSION.tar.gz" | sha1sum -c - && \ tar xf wildfly-$WILDFLY_VERSION.tar.gz && \ mv wildfly-$WILDFLY_VERSION $JBOSS_HOME && \ rm wildfly-$WILDFLY_VERSION.tar.gz USER root RUN curl -L -o jmx_prometheus_javaagent-$JMX_EXPORTER_VERSION.jar https://repo1.maven.org/maven2/io/prometheus/jmx/jmx_prometheus_javaagent/$JMX_EXPORTER_VERSION/jmx_prometheus_javaagent-$JMX_EXPORTER_VERSION.jar && \ echo "jmx_prometheus_javaagent-$JMX_EXPORTER_VERSION.jar" && \ mkdir -p /opt/jmx_exporter/ && \ mv jmx_prometheus_javaagent-$JMX_EXPORTER_VERSION.jar /opt/jmx_exporter/jmx_exporter.jar && \ chown jboss:jboss /opt/jmx_exporter/ ADD jmx_config.yaml /opt/jmx_exporter/jmx_config.yaml # Adjust WildFly configuration RUN sed -i -E "s:.*PRESERVE_JAVA_OPTS.*:. /etc/jboss-as/jboss-as.conf:" /opt/jboss/wildfly/bin/standalone.conf
jboss-config
-Xbootclasspath/a:/opt/jboss/wildfly/modules/system/layers/base/org/jboss/logmanager/main/jboss-logmanager-1.5.2.Final.jar:/opt/jboss/wildfly/modules/system/layers/base/org/jboss/logging/main/jboss-logging-3.1.4.GA.jar:/opt/jboss/wildfly/modules/system/layers/base/org/jboss/logmanager/main/jboss-logmanager-1.5.2.Final.jar \ -Dcom.sun.management.jmxremote \ -Dcom.sun.management.jmxremote.rmi.port=1234 \ -Dcom.sun.management.jmxremote.authenticate=false \ -Dcom.sun.management.jmxremote.ssl=false \ -Djboss.modules.system.pkgs=org.jboss.byteman,org.jboss.logmanager -Djava.util.logging.manager=org.jboss.logmanager.LogManager \ -Djava.util.logging.ConsoleHandler.level=ALL \ -Djava.rmi.server.hostname=hdap-api \ -javaagent:/opt/jmx_exporter/jmx_exporter.jar=1090:/opt/jmx_exporter/jmx_config.yaml \ "
Error日志
java.lang.ClassNotFoundException: org.jboss.logmanager.LogManager at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641) at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:525) at java.logging/java.util.logging.LogManager$1.run(LogManager.java:239) at java.logging/java.util.logging.LogManager$1.run(LogManager.java:223) at java.base/java.security.AccessController.doPrivileged(AccessController.java:318) at java.logging/java.util.logging.LogManager.<clinit>(LogManager.java:222) at java.logging/java.util.logging.Logger.demandLogger(Logger.java:649) at java.logging/java.util.logging.Logger.getLogger(Logger.java:718) at java.logging/java.util.logging.Logger.getLogger(Logger.java:702) at io.prometheus.jmx.shaded.io.prometheus.jmx.JmxCollector.<clinit>(JmxCollector.java:39) at io.prometheus.jmx.shaded.io.prometheus.jmx.JavaAgent.premain(JavaAgent.java:29) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:569) at java.instrument/sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:491) at java.instrument/sun.instrument.InstrumentationImpl.loadClassAndCallPremain(InstrumentationImpl.java:503) WARNING: Failed to load the specified log manager class org.jboss.logmanager.LogManager Exception in thread "main" java.lang.NoClassDefFoundError: org/jboss/logmanager/Level at java.base/java.lang.Class.forName0(Native Method) at java.base/java.lang.Class.forName(Class.java:467) at org.jboss.modules.Module.run(Module.java:341) at org.jboss.modules.Module.run(Module.java:321) at org.jboss.modules.Main.main(Main.java:604)
内容的提问来源于stack exchange,提问作者karthick M

