Micronaut 4.x应用编译Native Image报错,求GraalVM构建解决方案
问题背景
使用Micronaut Gradle AOT任务,将集成Pub/Sub与Kafka的Micronaut 4.6应用编译为Native Image时,BitBucket构建出现大量反射配置警告、类及方法未找到错误。
错误日志
警告:无法为反射配置解析类org.hamcrest.number.OrderingComparison。原因:java.lang.ClassNotFoundException: org.hamcrest.number.OrderingComparison。
警告:无法为反射配置解析类org.osgi.framework.BundleEvent。原因:java.lang.ClassNotFoundException: org.osgi.framework.BundleEvent。
警告:未找到方法ch.qos.logback.contrib.json.JsonFormatter.valueOf(String)。
警告:未找到方法ch.qos.logback.core.FileAppender.valueOf(String)。
警告:未找到方法ch.qos.logback.core.Layout.valueOf(String)。
警告:未找到方法ch.qos.logback.core.rolling.RollingPolicy.valueOf(String)。
警告:未找到方法ch.qos.logback.core.rolling.TriggeringPolicy.valueOf(String)。
警告:未找到方法ch.qos.logback.core.spi.ContextAware.valueOf(String)。
警告:无法为反射配置解析类reactor.core.publisher.Traces$StackWalkerCallSiteSupplierFactory。原因:java.lang.ClassNotFoundException: reactor.core.publisher.Traces$StackWalkerCallSiteSupplierFactory。
警告:无法为反射配置解析类reactor.core.publisher.Traces$ExceptionCallSiteSupplierFactory。原因:java.lang.ClassNotFoundException: reactor.core.publisher.Traces$ExceptionCallSiteSupplierFactory。
警告:无法为反射配置解析类io.opencensus.impl.trace.TraceComponentImpl。原因:java.lang.ClassNotFoundException: io.opencensus.impl.trace.TraceComponentImpl。
警告:无法为反射配置解析类io.opencensus.impl.metrics.MetricsComponentImpl。原因:java.lang.ClassNotFoundException: io.opencensus.impl.metrics.MetricsComponentImpl。
警告:无法为反射配置解析类com.google.auth.appengine.AppEngineCredentials。原因:java.lang.ClassNotFoundException: com.google.auth.appengine.AppEngineCredentials。
警告:无法为反射配置解析类org.apache.commons.pool2.impl.DefaultEvictionPolicy。原因:java.lang.ClassNotFoundException: org.apache.commons.pool2.impl.DefaultEvictionPolicy。
[1/8] 初始化中...
(19.0s @ 0.38GB) Java版本:17.0.9+9,供应商版本:GraalVM CE 17.0.9+9.1 Graal编译器:优化级别:2,目标机器:x86-64-v3 C编译器:gcc (redhat, x86_64, 11.3.1) 垃圾收集器:Serial GC(最大堆大小:RAM的80%)5个用户自定义特性:
com.google.api.gax.grpc.nativeimage.GrpcNettyFeature
com.google.api.gax.nativeimage.GoogleJsonClientFeature
com.google.api.gax.nativeimage.OpenCensusFeature
com.oracle.svm.thirdparty.gson.GsonFeature
io.micronaut.core.io.service.ServiceLoaderFeature
2024年11月18日 上午10:45:43
com.google.api.gax.nativeimage.NativeImageUtils
registerClassForReflection
警告:在类路径中未找到用于反射的io.grpc.netty.shaded.io.netty.channel.ProtocolNegotiators。
当前Gradle配置
plugins { id("org.jetbrains.kotlin.jvm") version "2.0.21" id("org.jetbrains.kotlin.plugin.allopen") version "2.0.21" id("com.google.devtools.ksp") version "2.0.21-1.0.27" id("com.google.cloud.tools.jib") version "3.4.2" id("jacoco") id("org.sonarqube") version "4.3.0.3225" id("com.github.johnrengelman.shadow") version "8.1.1" id("io.micronaut.application") version "4.4.4" id("org.jlleitschuh.gradle.ktlint") version "11.5.1" id("io.micronaut.aot") version "4.4.4" } micronaut { runtime(MicronautRuntime.NETTY) version.set("4.7.1") testRuntime(MicronautTestRuntime.JUNIT_5) processing { incremental = true annotations("de.foobar") } aot { optimizeServiceLoading = false convertYamlToJava = false precomputeOperations = true cacheEnvironment = true optimizeClassLoading = true deduceEnvironment = true optimizeNetty = true replaceLogbackXml = false netty { enabled = true } } } dependencies { ... // micronaut implementation("io.micronaut:micronaut-http-client") implementation("io.micronaut.gcp:micronaut-gcp-pubsub") implementation("io.micronaut.gcp:micronaut-gcp-secret-manager") implementation("io.micronaut.kafka:micronaut-kafka") implementation("io.micronaut.serde:micronaut-serde-jackson") implementation("io.micronaut.security:micronaut-security-jwt") implementation("io.micronaut.gcp:micronaut-gcp-logging") }
解决方案
1. 统一Micronaut插件与核心版本
当前Micronaut核心版本是4.7.1,但io.micronaut.application和io.micronaut.aot插件版本为4.4.4,版本不兼容会导致配置生成异常。将插件版本改为4.7.1:
id("io.micronaut.application") version "4.7.1" id("io.micronaut.aot") version "4.7.1"
2. 优化Micronaut AOT配置
- 开启
replaceLogbackXml:让AOT生成Native Image友好的Logback配置,避免对非枚举类的valueOf反射调用(这正是Logback相关警告的根源) - 开启
optimizeServiceLoading:减少ServiceLoader的反射依赖
修改后的AOT配置:
aot { optimizeServiceLoading = true convertYamlToJava = false precomputeOperations = true cacheEnvironment = true optimizeClassLoading = true deduceEnvironment = true optimizeNetty = true replaceLogbackXml = true netty { enabled = true } }
3. 处理缺失的可选依赖类
大部分找不到的类属于可选依赖或测试依赖,无需引入生产环境:
org.hamcrest类:属于测试依赖,若确认生产代码未使用,可忽略该警告,或在反射配置中排除com.google.auth.appengine.AppEngineCredentials:仅在GCP App Engine环境需要,若部署环境非App Engine,可通过排除依赖移除相关配置:implementation("io.micronaut.gcp:micronaut-gcp-pubsub") { exclude group: "com.google.auth", module: "google-auth-library-appengine" }io.opencensus.impl.*:若不需要OpenCensus监控,可禁用GCP的OpenCensus特性,或添加OpenCensus实现依赖:runtimeOnly("io.opencensus:opencensus-impl") runtimeOnly("io.opencensus:opencensus-impl-core")org.apache.commons.pool2.impl.DefaultEvictionPolicy:添加Commons Pool2依赖(若Kafka客户端需要连接池):runtimeOnly("org.apache.commons:commons-pool2")
4. 修复gRPC/Netty反射警告
针对io.grpc.netty.shaded.io.netty.channel.ProtocolNegotiators找不到的问题,添加gRPC Netty Shaded依赖:
runtimeOnly("io.grpc:grpc-netty-shaded:1.64.0") // 版本与Micronaut GCP依赖匹配
5. 自定义Native Image反射配置(可选)
若仍有无法解决的警告,可在src/main/resources/META-INF/native-image/reflect-config.json中添加配置,排除不需要的类或方法:
[ { "name": "org.hamcrest.number.OrderingComparison", "condition": { "typeReachable": "org.junit.Assert" } }, { "name": "ch.qos.logback.core.FileAppender", "methods": [] // 移除错误的valueOf方法配置 } ]
内容的提问来源于stack exchange,提问作者Mr.Mountain

