native 故障排查与 FAQ
2026年8月12日 上午11:32:48
native 构建出错是常态(native 导引 里有心理准备提示)。本文把最常见的报错、定位思路和常见问题汇总成一张对照表,按图索骥即可。
1、典型报错对照表
| 报错/现象 | 原因 | 处理 |
|---|---|---|
Abstract classes are not supported as proxy components | 代理组件是抽象类 | 去掉代理或改造类(见 《native 约束与兼容性》) |
Final classes are not supported as proxy components | 代理组件是 final 类 | 去掉 final |
Not public classes are not supported as proxy components | 代理组件不是 public | 改成 public |
Generic type classes are not supported as proxy components | 代理组件是泛型类 | 去掉类型参数 |
| 打包时提示连接 DB/Redis 失败 | AOT 阶段真实启动了应用,依赖本地服务 | 打包前起好服务,或 NativeDetector.isNotAotRuntime() 跳过(见 《native 约束与兼容性》) |
ClassNotFoundException: xxx(native 运行时) | 类未被登记反射/未被包含 | 看 target/classes/META-INF/native-image/.../reflect-config.json 是否登记;没有则手动登记 |
MissingReflectionRegistrationError | 反射调用目标类未登记 | 在 《native 项目开发定制》 的 Registrar 里补 registerReflection |
java.io.FileNotFoundException(资源找不到) | 资源未登记 | 补 registerResourceInclude |
NoSuchMethodError / NoSuchFieldError(native 运行时) | 方法/字段未登记 | 补 registerMethod / registerField 或对应 MemberCategory |
序列化抛 InvalidClassException / 反序列化失败 | 类未登记序列化 | 补 registerSerialization(方法参数/返回值会自动登记,见 《native 自动化处理清单》) |
| native 构建 OOM / 卡死 | 构建机内存不足 | 加内存或调整 native-image 构建参数 |
| native 构建失败:找不到 gcc/链接器 | 缺 OS 原生工具链 | 装 Xcode CLT / gcc+glibc-devel / VS Build Tools(见 《native 环境准备》) |
AOT 阶段 main 抛业务异常导致打包中断 | 启动代码有问题 | 排查启动逻辑,或条件化跳过(同第 5 行) |
运行期 ScanUtil 扫不到资源 | 资源未进 solon-resource.json | 确认资源在 include 清单里,或用 registerResourceInclude 登记 |
2、标准排查流程
- 确认 AOT 产物是否生成:看
target/classes/META-INF/native-image/<应用包路径>/下 5 个 json/properties 文件是否存在(《native 自动化处理清单》)。 - 确认报错类是否已登记:在 reflect-config.json / serialization-config.json / resource-config.json 里搜报错的类名或资源名。
- 没登记 → 补登记:在
RuntimeNativeRegistrar实现里补对应 API(参考 《native RuntimeNativeRegistrar API 参考》),重新打包。 - 已登记仍报错:检查登记粒度是否够(比如只登记了 INTROSPECT 但需要 INVOKE;只登记了类但没登记字段/方法)。
- 还不行:看是否用了动态编译/字节码生成(A/B 类第三方库),考虑换库或换方案。
3、FAQ
- Q1:需要手动加 solon-aot 依赖吗?
不需要。solon-parent 的 -P aot / -P native profile 会自动引入 solon-aot 依赖并挂载 process-aot 插件。手动加依赖只在不用官方 profile 时才有意义。
- Q2:
-P aot和-P native有什么区别?
-P aot:执行 AOT 处理(生成代理源码 + 原生元数据),任意 JDK 可用;-P native:AOT 处理 + GraalVM 原生编译,需要 graalvm jdk17+,且启用官方可达性元数据仓库。
- Q3:为什么打包时我的 main 方法会被执行?
AOT 需要"真实启动"应用来收集容器信息,这是设计行为。启动副作用代码用 NativeDetector.isNotAotRuntime() 包裹即可。
- Q4:为什么 native 下
Class.forName找不到类?
native 镜像只包含构建时可达的类。运行期动态加载的类不会进入镜像,需手动登记并确认该类被包含。
- Q5:native 镜像能跑 Java 序列化吗?
能,但序列化类必须登记(registerSerialization)。方法参数/返回值会自动登记,其余需手动。
- Q6:为什么 native 镜像比 JVM 包大 / 小?
native 只打包可达代码,通常更小;但大量反射登记(尤其 INVOKE)会增大镜像。按需登记、多用 INTROSPECT 少用 INVOKE 可控制体积。
- Q7:多模块项目 AOT 怎么处理?
只有主模块执行 AOT,其它模块常规构建。所有模块先 mvn install,主模块 AOT 时通过扩展加载机制合并各模块的 reflect-config.json / solon-resource.json(见 《aot 项目编译示范》)。
- Q8:第三方库支持情况怎么判断?
按 《native 项目开发定制》 的 A/B/C/D 分类:D 类(自带元数据)直接用;C 类补少量配置;B 类要实验调配置;A 类(动态编译/字节码)不支持。