基于Struts2的Java17应用升级log4j-api至2.20.0遇初始化错误求助
问题
基于struts2-core:6.3.0.2开发的Java 17.0.5应用,依赖log4j-api:2.17.2时运行正常。将log4j-api升级至Struts官方支持的2.20.0版本后,应用启动触发初始化异常,添加log4j-core:2.20.0至类路径后问题仍未解决。
异常信息如下:
SEVERE [main] org.apache.catalina.core.StandardContext.filterStart Exception starting filter [Struts2Filter] java.lang.NoClassDefFoundError: Could not initialize class org.apache.logging.log4j.util.PropertiesUtil at org.apache.logging.log4j.status.StatusLogger.<clinit>(StatusLogger.java:77) at org.apache.logging.log4j.LogManager.<clinit>(LogManager.java:61) at org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter.<clinit>(StrutsPrepareAndExecuteFilter.java:49) at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499) at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480) at org.apache.catalina.core.DefaultInstanceManager.newInstance(DefaultInstanceManager.java:143) at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:242) at org.apache.catalina.core.ApplicationFilterConfig.<init>(ApplicationFilterConfig.java:97) at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:4311) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:4940) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:171) at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:683) at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:658) at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:661) at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:1014) at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1866) at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75) at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:123) at org.apache.catalina.startup.HostConfig.deployWARs(HostConfig.java:816) at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:468) at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1584) at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:312) at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:114) at org.apache.catalina.util.LifecycleBase.setStateInternal(LifecycleBase.java:402) at org.apache.catalina.util.LifecycleBase.setState(LifecycleBase.java:345) at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:893) at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:794) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:171) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1332) at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1322) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75) at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:145) at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:866) at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:248) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:171) at org.apache.catalina.core.StandardService.startInternal(StandardService.java:433) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:171) at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:925) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:171) at org.apache.catalina.startup.Catalina.start(Catalina.java:735) 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:568) at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:345) at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:473) Caused by: java.lang.ExceptionInInitializerError: Exception java.lang.IllegalArgumentException: key can't be empty [in thread "main"] at java.base/java.lang.System.checkKey(System.java:1049) at java.base/java.lang.System.getProperty(System.java:912) at org.apache.logging.log4j.util.SystemPropertiesPropertySource.getProperty(SystemPropertiesPropertySource.java:96) at org.apache.logging.log4j.util.SystemPropertiesPropertySource.containsProperty(SystemPropertiesPropertySource.java:104) at org.apache.logging.log4j.util.PropertiesUtil$Environment.lambda$null$2(PropertiesUtil.java:498) at java.base/java.lang.Iterable.forEach(Iterable.java:75) at org.apache.logging.log4j.util.PropertiesUtil$Environment.lambda$reload$3(PropertiesUtil.java:497) at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) at java.base/java.util.HashMap$KeySpliterator.forEachRemaining(HashMap.java:1707) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) at org.apache.logging.log4j.util.PropertiesUtil$Environment.reload(PropertiesUtil.java:494) at org.apache.logging.log4j.util.PropertiesUtil$Environment.<init>(PropertiesUtil.java:469) at org.apache.logging.log4j.util.PropertiesUtil$Environment.<init>(PropertiesUtil.java:444) at org.apache.logging.log4j.util.PropertiesUtil.<init>(PropertiesUtil.java:88) at org.apache.logging.log4j.util.PropertiesUtil.<init>(PropertiesUtil.java:80) at org.apache.logging.log4j.util.PropertiesUtil.<clinit>(PropertiesUtil.java:56) at org.apache.logging.log4j.util.Constants.<clinit>(Constants.java:30) at org.apache.logging.log4j.spi.AbstractLogger.createClassForProperty(AbstractLogger.java:203) at org.apache.logging.log4j.spi.AbstractLogger.<clinit>(AbstractLogger.java:92) ... 51 more
解决方案
从异常根因java.lang.IllegalArgumentException: key can't be empty可以看出,Log4j 2.20.0在初始化PropertiesUtil时会严格校验系统属性的键合法性,而你的运行环境中存在空键的系统属性(比如错误的JVM启动参数-D=、空名称的环境变量),旧版本2.17.2没有该校验逻辑,因此之前运行正常。
按以下步骤排查解决:
- 检查JVM启动参数:查看IDE的VM选项、Tomcat启动脚本(catalina.sh/catalina.bat),删除类似
-D=这类无效的空键参数。 - 清理环境变量:排查系统或用户环境变量中是否存在空名称的变量,这类变量会被自动转为系统属性,导致空键问题。
- 校验依赖一致性:确保
log4j-api和log4j-core版本完全一致(均为2.20.0),用依赖分析工具(Maven执行mvn dependency:tree,Gradle执行gradle dependencies)排查是否有旧版本Log4j类残留,排除冲突依赖。 - 检查Tomcat配置:如果部署在Tomcat中,确认
setenv.sh/setenv.bat里没有错误的环境变量配置,避免生成空键系统属性。
内容的提问来源于stack exchange,提问作者kritarth
相关产品推荐
相关产品推荐

