使用Quarkus构建GraalVM原生镜像遇未解析类型错误:Log4J2Logger
我用Quarkus框架构建GraalVM原生镜像时触发了错误,我的Gradle依赖配置如下:
dependencies { implementation(enforcedPlatform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}")) implementation("io.quarkus:quarkus-kotlin") implementation("io.quarkus:quarkus-kubernetes") implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") implementation("io.quarkus:quarkus-arc") testImplementation("io.quarkus:quarkus-junit5") implementation("io.temporal:temporal-sdk:1.21.0") }
错误信息如下:
导致错误的原因:
org.graalvm.compiler.java.BytecodeParser$BytecodeParserError:
com.oracle.graal.pointsto.constraints.UnresolvedElementException:
解析过程中发现未解析的类型:io.grpc.netty.shaded.io.netty.util.internal.logging.Log4J2Logger。
此错误在镜像构建阶段上报,因为类io.grpc.netty.shaded.io.netty.util.internal.logging.Log4J2LoggerFactory已通过命令行注册为镜像构建阶段链接的类,
错误发生在解析io.grpc.netty.shaded.io.netty.util.internal.logging.Log4J2LoggerFactory.newInstance(Log4J2LoggerFactory.java:33)时
at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.throwParserError(BytecodeParser.java:2536)
at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.phases.SharedGraphBuilderPhase$SharedBytecodeParser.throwParserError(SharedGraphBuilderPhase.java:169)
解决方案
这个错误源于Temporal SDK依赖的gRPC Netty shaded包尝试加载Log4J2相关类,但Quarkus默认日志组件并非Log4J2,导致GraalVM构建原生镜像时找不到对应类。可通过以下方式解决:
方式一:添加Log4J2依赖并切换Quarkus日志实现
在Gradle依赖中添加:implementation("io.quarkus:quarkus-logging-log4j2")添加后Quarkus会自动切换为Log4J2日志实现,GraalVM即可找到对应类。
方式二:排除Log4J2依赖并指定Netty使用SLF4J
修改Temporal SDK依赖配置,排除Log4J2相关依赖,同时添加Netty SLF4J桥接包:implementation("io.temporal:temporal-sdk:1.21.0") { exclude group: 'org.apache.logging.log4j' } implementation("io.netty:netty-slf4j-handler:4.1.94.Final")同时在
application.properties中添加配置强制Netty使用SLF4J:io.netty.util.internal.logging.InternalLoggerFactory=io.netty.util.internal.logging.Slf4JLoggerFactory方式三:通过GraalVM配置注册缺失类
在src/main/resources/META-INF/native-image/目录下创建reflect-config.json文件,添加内容:[ { "name": "io.grpc.netty.shaded.io.netty.util.internal.logging.Log4J2Logger", "allDeclaredConstructors": true, "allPublicConstructors": true, "allDeclaredMethods": true, "allPublicMethods": true } ]此方式直接告知GraalVM构建时包含该类,但如果该类依赖其他Log4J2组件,可能需要补充更多配置,建议优先使用前两种方式。
内容的提问来源于stack exchange,提问作者Gireesh

