尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
GraalVM 21 Native Image 编译踩坑全记录:从 class 初始化冲突到成功构建
环境信息项目版本/信息GraalVM21.0.127-LTS (Oracle GraalVM)Spring Boot3.4.5native-maven-plugin0.10.6操作系统Windows 25H2C 编译器cl.exe (Microsoft x64 19.51.36256)项目背景Spring Boot 3.x 智能客服项目集成了 Nacos配置中心/服务注册、Milvus向量数据库、Logback日志、MyBatis-Plus、Elasticsearch、Redis 等组件。配置了 Maven 双 ProfileJVM / Native支持 GraalVM AOT 编译。编译命令是mvn clean -Pnative native:compile -X第一阶段grpc-netty-shaded 类初始化冲突不可调和错误现象Error: Classes that should be initialized at run time got initialized during image building:io.grpc.netty.shaded.io.netty.util.AbstractReferenceCounted was unintentionally initialized at build time....27 个 netty 类根因分析Nacos 2.x 通过nacos-client传递依赖grpc-netty-shaded该 jar 内嵌META-INF/native-image/native-image.properties声明了所有 netty 类为--initialize-at-run-time。但 native-image builder 的 points-to 分析阶段会通过ensureClassInitialized强制在构建时初始化这些类两者不可调和。GraalVM 21 硬性阻止从 RUN_TIME 改为 BUILD_TIMEClassInitializationConfiguration.insertRec()方法报 Incompatible change of initialization policy。排查过程最初以为是 Nacos 独有来源排除nacos-client后发现grpc-netty-shaded仍在 classpath 上mvn dependency:tree -Pnative -Dincludesio.grpc:grpc-netty-shaded发现第二条依赖链langchain4j-milvus → milvus-sdk-java → grpc-netty-shaded:1.59.1最终方案将两个冲突源的依赖 scope 设为 provided编译可用native-image 运行时不在 classpathprofile idnative/id dependencies !-- Nacos: grpc-netty-shaded via nacos-client -- dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId scopeprovided/scope /dependency dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-alibaba-nacos-config/artifactId scopeprovided/scope /dependency dependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-starter-bootstrap/artifactId scopeprovided/scope /dependency !-- Milvus: grpc-netty-shaded via milvus-sdk-java -- dependency groupIddev.langchain4j/groupId artifactIdlangchain4j-milvus/artifactId scopeprovided/scope /dependency /dependencies /profile注意不能简单用exclusions排除nacos-client因为spring-cloud-starter-alibaba-nacos-logging子模块会引用nacos-client的NacosLogging类导致NoClassDefFoundError。providedscope 是更干净的方案。第二阶段Logback/SLF4J 类初始化冲突通配符陷阱错误现象排除 grpc-netty-shaded 后构建继续报错Error: Classes that should be initialized at run time got initialized during image building:ch.qos.logback.core.status.StatusBase was unintentionally initialized at build time.ch.qos.logback.classic.Logger was unintentionally initialized at build time.org.slf4j.LoggerFactory was unintentionally initialized at build time.org.apache.commons.logging.LogFactory was unintentionally initialized at build time....共 11 个类踩坑 1**通配符不生效首先在pom.xml的buildArgs中添加buildArg--initialize-at-build-timech.qos.logback.**,org.slf4j.**,org.apache.commons.logging.**/buildArg结果完全无效同样的错误。踩坑 2*通配符也不生效改为单星号buildArg--initialize-at-build-timech.qos.logback.*,org.slf4j.*,org.apache.commons.logging.*/buildArg结果同样无效。根因GraalVM 21 的通配符语义GraalVM 21 的ClassInitializationConfiguration使用startsWith 边界检查的匹配逻辑。**和*在包名模式中的行为与直觉不符——它们并不像 Ant 风格 glob 那样工作。经过实测验证GraalVM 21 的通配符对这些类不生效必须使用显式类名。最终方案显式列出所有 11 个类buildArg--initialize-at-build-timech.qos.logback.core.status.StatusBase,ch.qos.logback.core.status.InfoStatus,ch.qos.logback.core.util.StatusPrinter,ch.qos.logback.core.util.StatusPrinter2,ch.qos.logback.core.util.Loader,ch.qos.logback.classic.Logger,ch.qos.logback.classic.Level,org.slf4j.LoggerFactory,org.slf4j.helpers.Reporter,org.apache.commons.logging.LogFactory,org.apache.commons.logging.impl.Jdk14Logger/buildArg结果类初始化错误全部消失构建进入下一阶段。第三阶段JDK Console 相关类冲突连环坑错误 1ProxyingConsole 堆对象错误Error: An object of type java.io.ProxyingConsole was found in the image heap.Trace: Object was reached bytrying to constant fold static field sun.security.util.Password$ConsoleHolder.c1builder 分析阶段尝试常量折叠Password$ConsoleHolder.c1静态字段该字段持有ProxyingConsole对象。但ProxyingConsole被标记为 RUN_TIME不允许出现在 image heap 中。尝试修复添加--initialize-at-build-timejava.io.ProxyingConsole错误 2Console 继承链冲突Error: Incompatible change of initialization policy for java.io.Console:trying to change BUILD_TIME super type of java.io.ProxyingConsole to RUN_TIMEfor JDK native code support via JNIProxyingConsole extends Console而 GraalVM 21 的 JDK JNI 注册要求java.io.Console保持 RUN_TIME。强制ProxyingConsole为 BUILD_TIME 会级联要求父类Console也变为 BUILD_TIME与 JDK 原生注册冲突。结论不能将ProxyingConsole设为 BUILD_TIME必须从源头阻止对象创建。错误 3级联初始化失败改为--initialize-at-run-timesun.security.util.Password$ConsoleHolder后Class initialization of jdk.internal.io.JdkConsoleImpl$1ConsoleHolder failed.java.lang.IllegalStateException: Cant create a dedicated password consolesince a real console already existsPassword$ConsoleHolder的clinit触发了JdkConsoleImpl$1ConsoleHolder的初始化后者在构建环境中失败没有可用的专用密码控制台。最终方案同时标记两个 JDK 内部类为 RUN_TIMEbuildArg--initialize-at-run-timejdk.internal.io.JdkConsoleImpl$1ConsoleHolder,sun.security.util.Password$ConsoleHolder/buildArgPassword$ConsoleHolder→ RUN_TIME阻止构建时创建ProxyingConsole对象JdkConsoleImpl$1ConsoleHolder→ RUN_TIME阻止级联初始化崩溃结果构建成功通过最终配置总览pom.xml native profile 关键配置profile idnative/id dependencies !-- grpc-netty-shaded 冲突源provided scope 排除 -- dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId scopeprovided/scope /dependency dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-alibaba-nacos-config/artifactId scopeprovided/scope /dependency dependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-starter-bootstrap/artifactId scopeprovided/scope /dependency dependency groupIddev.langchain4j/groupId artifactIdlangchain4j-milvus/artifactId scopeprovided/scope /dependency /dependencies build plugins plugin groupIdorg.graalvm.buildtools/groupId artifactIdnative-maven-plugin/artifactId version0.10.6/version extensionstrue/extensions executions execution idbuild-native/id goalsgoalcompile/goal/goals phasepackage/phase /execution execution iddefault-cli/id goalsgoalcompile/goal/goals phasepackage/phase configuration buildArgs buildArg--initialize-at-build-timech.qos.logback.core.status.StatusBase,ch.qos.logback.core.status.InfoStatus,ch.qos.logback.core.util.StatusPrinter,ch.qos.logback.core.util.StatusPrinter2,ch.qos.logback.core.util.Loader,ch.qos.logback.classic.Logger,ch.qos.logback.classic.Level,org.slf4j.LoggerFactory,org.slf4j.helpers.Reporter,org.apache.commons.logging.LogFactory,org.apache.commons.logging.impl.Jdk14Logger/buildArg buildArg--initialize-at-run-timejdk.internal.io.JdkConsoleImpl$1ConsoleHolder,sun.security.util.Password$ConsoleHolder/buildArg /buildArgs /configuration /execution /executions configuration buildArgs buildArg--initialize-at-build-timech.qos.logback.core.status.StatusBase,ch.qos.logback.core.status.InfoStatus,ch.qos.logback.core.util.StatusPrinter,ch.qos.logback.core.util.StatusPrinter2,ch.qos.logback.core.util.Loader,ch.qos.logback.classic.Logger,ch.qos.logback.classic.Level,org.slf4j.LoggerFactory,org.slf4j.helpers.Reporter,org.apache.commons.logging.LogFactory,org.apache.commons.logging.impl.Jdk14Logger/buildArg buildArg--initialize-at-run-timejdk.internal.io.JdkConsoleImpl$1ConsoleHolder,sun.security.util.Password$ConsoleHolder/buildArg /buildArgs /configuration /plugin /plugins /build /profilenative-image.propertiesArgs -H:IncludeResources.*\\.xml$|.*\\.yml$|.*\\.properties$|.*\\.md$|.*\\.sql$ \ --no-fallback \ -H:ReportExceptionStackTraces踩坑经验总结#坑教训1grpc-netty-shaded的 RUN_TIME 声明不可覆盖GraalVM 21 硬性阻止 RUN_TIME → BUILD_TIME 的策略变更唯一方案是排除依赖2**通配符在 GraalVM 21 中不生效ClassInitializationConfiguration使用startsWith匹配**被当作字面字符3*通配符同样不生效单星号也不匹配子包中的类必须使用显式类名4--initialize-at-build-timeProxyingConsole与 JDK JNI 冲突ProxyingConsole extends Console父类Console被 JDK 原生注册锁定为 RUN_TIME5只标记Password$ConsoleHolder为 RUN_TIME 会级联崩溃其clinit触发JdkConsoleImpl$1ConsoleHolder初始化必须两者同时标记6XML 注释中不能包含--pom.xml 的 XML 注释中写--initialize-at-run-time会导致解析错误7providedscope 优于exclusions排除传递依赖的子模块可能引用被排除 jar 的类provided更干净Native 模式限制功能JVM 模式Native 模式Nacos 配置中心/服务注册✅❌ (使用本地 application.yml)Milvus 向量存储✅❌ (provided scope 排除)其他所有功能✅✅希望这篇记录能帮助遇到类似问题的同学。GraalVM Native Image 的编译错误排查核心思路仔细阅读错误信息中的 trace 和 suggestion它们通常已经给出了精确的修复方向
RELATED

相关推荐

从编译到部署:一个Java服务的完整旅程

从编译到部署:一个Java服务的完整旅程

当你写下public class OrderService {的那一刻,契约已经达成。编译器不会眨眼看你的意图,它只是把缩进和花括号翻译成一串冷酷的字节。一个Java服务的生命,从这里开始,却远不止你眼前的IDE。从.java到线上正在处理真实订单的进程&…

📅 2026/11/4 7:55:25
AI插件标准与MCP:从统一接入到工程实践

AI插件标准与MCP:从统一接入到工程实践

先说一个很多开发者最近都会遇到的场景:电脑里装了好几个 AI 编程工具,一会儿要在编辑器里装个插件,一会儿要开一个命令行工具处理仓库级任务,一会儿又要接一个外部知识库。每个工具都能干点事,但它们的配置方式、上下…

📅 2026/10/5 10:49:16
Java List源码与面试实战:从ArrayList底层到排序与线程安全

Java List源码与面试实战:从ArrayList底层到排序与线程安全

很多年前我面大厂的时候,遇到一个场景题:线上有个接口频繁 Full GC,排查下来是某个高频查询里用 List.contains 做了大批量判断,而那个 List 是 LinkedList 。当时我第一反应是“用 HashSet 替换啊”,但面试官紧…

📅 2026/10/8 5:20:45
MORE NEWS

更多资讯

📰

前缀和与前后缀分解算法详解及应用

1. 题目背景与核心问题解析 这道题目来自USACO 2024年公开赛的铜组B题,题目编号P10274。作为一道面向算法初学者的普及难度题目,它考察的是基础数据结构与算法思想的应用能力。题目名称中的"Logical Moos"暗示了题目内容与逻辑判断和数据处理相…

📰

雷池WAF离线部署与金融行业安全防护实践

1. 项目概述 雷池WAF(Web Application Firewall)是一款专注于保护Web应用安全的防护系统。它通过分析HTTP/HTTPS流量,能够有效防御SQL注入、XSS跨站脚本、CSRF等常见Web攻击。在实际企业环境中,由于安全合规要求或网络环境限制&am…

📰

PowerBuilder数据库开发实战:从案例源码到事务管理与数据窗口

简介:这份资源面向希望系统掌握 PowerBuilder 数据库开发的中初级开发者与维护老系统的技术人员,以经典案例解析为主线,帮助读者从数据窗口设计、事件处理、事务管理到报表图表、数据源连接等环节建立完整的实践认知。压缩包共 172 个文件&am…

📰

2025-2026网络与信息安全毕设选题:易通过、可落地、能答辩

每年十月到十二月,我这边收到的私信里,问得最多的一类就是:"网络与信息安全专业毕设题目到底怎么选,才能稳稳过?"问的人背景差得挺远,有的是科班出身但实践少,有的是跨专业刚补完基础…

📰

网络与信息安全毕业设计易通过选题:边界、闭环与十周推进

1. “易通过”的题到底长什么样:先把评判标准摆上桌 每年到了这个时候,我都会被问到同一个问题:网络与信息安全专业的毕业设计选题,到底怎么挑才不会做到一半崩掉。问的人里有的是自己心里没底,有的是被导师打回来两次…

📰

移动端Web测试代理工具Fiddler与Charles深度解析

1. 移动端Web测试中的代理工具核心价值 在移动应用开发与测试领域,网络通信的可见性始终是调试和优化的关键瓶颈。不同于桌面浏览器提供的开发者工具,移动端环境(特别是原生应用内嵌的WebView)往往缺乏原生的网络监控界面。这正是…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬