升级log4j-layout-template-json后出现IllegalAccessError问题求助
在OpenJDK 17环境下运行Spring Boot应用,使用log4j-layout-template-json包输出JSON格式日志到标准输出。此前使用2.17.2版本一切正常,升级到2.18.0后,应用每次尝试记录日志都会抛出如下错误:
2022-12-13 10:28:59,028 main ERROR An exception occurred processing Appender Console org.apache.logging.log4j.core.appender.AppenderLoggingException: java.lang.IllegalAccessError: class org.apache.logging.log4j.layout.template.json.JsonTemplateLayout$StringBuilderEncoder tried to access method 'void org.apache.logging.log4j.core.layout.TextEncoderHelper.encodeText(java.nio.charset.CharsetEncoder, java.nio.CharBuffer, java.nio.ByteBuffer, java.lang.StringBuilder, org.apache.logging.log4j.core.layout.ByteBufferDestination)' (org.apache.logging.log4j.layout.template.json.JsonTemplateLayout$StringBuilderEncoder and org.apache.logging.log4j.core.layout.TextEncoderHelper are in unnamed module of loader org.springframework.boot.loader.LaunchedURLClassLoader @76fb509a) at org.apache.logging.log4j.core.config.AppenderControl.tryCallAppender(AppenderControl.java:165) at org.apache.logging.log4j.core.config.AppenderControl.callAppender0(AppenderControl.java:134) at org.apache.logging.log4j.core.config.AppenderControl.callAppenderPreventRecursion(AppenderControl.java:125) at org.apache.logging.log4j.core.config.AppenderControl.callAppender(AppenderControl.java:89) at org.apache.logging.log4j.core.config.LoggerConfig.callAppenders(LoggerConfig.java:675) at org.apache.logging.log4j.core.config.LoggerConfig.processLogEvent(LoggerConfig.java:633) at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:616) at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:552) at org.apache.logging.log4j.core.config.AwaitCompletionReliabilityStrategy.log(AwaitCompletionReliabilityStrategy.java:82) at org.apache.logging.log4j.core.Logger.log(Logger.java:161) at org.apache.logging.log4j.spi.AbstractLogger.tryLogMessage(AbstractLogger.java:2205) at org.apache.logging.log4j.spi.AbstractLogger.logMessageTrackRecursion(AbstractLogger.java:2159) at org.apache.logging.log4j.spi.AbstractLogger.logMessageSafely(AbstractLogger.java:2142) at org.apache.logging.log4j.spi.AbstractLogger.logMessage(AbstractLogger.java:1994) at org.apache.logging.log4j.spi.AbstractLogger.logIfEnabled(AbstractLogger.java:1852) at org.apache.commons.logging.LogAdapter$Log4jLog.log(LogAdapter.java:270) at org.apache.commons.logging.LogAdapter$Log4jLog.info(LogAdapter.java:230) at org.springframework.boot.StartupInfoLogger.logStarting(StartupInfoLogger.java:55) at org.springframework.boot.SpringApplication.logStartupInfo(SpringApplication.java:618) at org.springframework.boot.SpringApplication.prepareContext(SpringApplication.java:377) at org.springframework.boot.SpringApplication.run(SpringApplication.java:307) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) at org.engine.App.main(App.java:40) 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.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) at org.springframework.boot.loader.Launcher.launch(Launcher.java:108) at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:65) Caused by: java.lang.IllegalAccessError: class org.apache.logging.log4j.layout.template.json.JsonTemplateLayout$StringBuilderEncoder tried to access method 'void org.apache.logging.log4j.core.layout.TextEncoderHelper.encodeText(java.nio.charset.CharsetEncoder, java.nio.CharBuffer, java.nio.ByteBuffer, java.lang.StringBuilder, org.apache.logging.log4j.core.layout.ByteBufferDestination)' (org.apache.logging.log4j.layout.template.json.JsonTemplateLayout$StringBuilderEncoder and org.apache.logging.log4j.core.layout.TextEncoderHelper are in unnamed module of loader org.springframework.boot.loader.LaunchedURLClassLoader @76fb509a) at org.apache.logging.log4j.layout.template.json.JsonTemplateLayout$StringBuilderEncoder.encode(JsonTemplateLayout.java:241) at org.apache.logging.log4j.layout.template.json.JsonTemplateLayout$StringBuilderEncoder.encode(JsonTemplateLayout.java:216) at org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.encode(JsonTemplateLayout.java:304) at org.apache.logging.log4j.layout.template.json.JsonTemplateLayout.encode(JsonTemplateLayout.java:58) at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.directEncodeEvent(AbstractOutputStreamAppender.java:215) at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.tryAppend(AbstractOutputStreamAppender.java:208) at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.append(AbstractOutputStreamAppender.java:199) at org.apache.logging.log4j.core.config.AppenderControl.tryCallAppender(AppenderControl.java:161) ... 31 more
升级到2.19.0版本后问题依然存在,且仅在执行打包后的应用Jar时触发,使用Maven运行Surefire/Failsafe测试时无异常。
环境信息
Java版本
$ java --version openjdk 17.0.5 2022-10-18 OpenJDK Runtime Environment (build 17.0.5+8-Ubuntu-2ubuntu120.04) OpenJDK 64-Bit Server VM (build 17.0.5+8-Ubuntu-2ubuntu120.04, mixed mode, sharing)
Pom.xml片段
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.3</version> <relativePath/> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-layout-template-json</artifactId> <version>2.18.0</version> </dependency> </dependencies>
Log4j配置文件
<?xml version="1.0" encoding="UTF-8"?> <Configuration> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <JsonTemplateLayout eventTemplateUri="classpath:JSONLogLayout.json"></JsonTemplateLayout> </Console> </Appenders> <Loggers> <logger name="org.jooq" level="warn" additivity="false"> <appender-ref ref="Console" /> </logger> <Root level="info"> <AppenderRef ref="Console"/> </Root> </Loggers> </Configuration>
问题根源
Spring Boot 2.7.3的parent依赖默认管理的Log4j2版本是2.17.2,但手动将log4j-layout-template-json升级到了2.18.0/2.19.0,导致Log4j2组件版本不一致。2.18.0版本的JsonTemplateLayout$StringBuilderEncoder尝试调用TextEncoderHelper中一个访问权限被修改的方法,而核心的log4j-core还是2.17.2版本,因此触发IllegalAccessError。
修复步骤
方法1:统一Log4j2所有组件版本
在pom.xml的<properties>中指定统一的Log4j2版本,让所有相关依赖自动对齐该版本:
<properties> <log4j2.version>2.19.0</log4j2.version> </properties>
同时移除log4j-layout-template-json依赖中的手动版本指定:
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-layout-template-json</artifactId> </dependency>
方法2:降级回兼容版本
如果不需要升级Log4j2,直接将log4j-layout-template-json版本改回2.17.2,与Spring Boot parent管理的版本保持一致:
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-layout-template-json</artifactId> <version>2.17.2</version> </dependency>
方法3:升级Spring Boot版本
将Spring Boot parent版本升级到支持更高Log4j2版本的分支(如2.7.x后续版本或3.x),确保其默认管理的Log4j2版本与你使用的log4j-layout-template-json版本匹配。
测试环境无异常原因
测试时使用的类加载器环境与打包后的Spring Boot LaunchedURLClassLoader不同,测试阶段依赖可能被统一加载,或类加载顺序避免了版本冲突,因此未触发错误。
内容的提问来源于stack exchange,提问作者yobb

