---
title: "native 自动化处理清单"
---

Solon AOT 在编译时会**自动启动一次应用**（用于收集容器信息），然后把能探测到的东西全部登记成 GraalVM 原生元数据。本文回答两个问题：

1. 框架自动替你做了什么？（开箱即用清单）
2. 框架不自动处理什么？（需要手动登记的部分）


### 1、AOT 阶段自动完成的四件事

执行 `-P aot`（或 `-P native`）打包时，`solon-maven-plugin:process-aot` 会触发 `SolonAotProcessor`：

| 步骤 | 说明 |
| --- | --- |
| 1. 真实启动应用 | 调用主类的 `main` 方法启动 Solon（`NativeDetector.isAotRuntime()` 为 true），通过自然运行收集容器信息 |
| 2. 生成代理类 Java 源码 | 为被代理的 bean 生成 `Xxx$$SolonAotProxy.java`（javapoet 生成源码，由 Maven 编译，运行时不再需要 ASM） |
| 3. 生成原生元数据 | 写出 reflect-config.json 、 resource-config.json 、 serialization-config.json 、 proxy-config.json 、 native-image.properties |
| 4. 生成 Solon 私有资源索引 | 把扫描到的资源清单写入 solon-resource.json，供 native 运行时做资源扫描 |

产物统一输出到：`target/classes/META-INF/native-image/<应用包路径>/`


### 2、自动注册的"类"（→ reflect-config.json）

| 自动注册内容 | 注册粒度 | 备注 |
| --- | --- | --- |
| 所有非接口 bean 类 | 默认构造（若有）+ `DECLARED_FIELDS` + `INVOKE_DECLARED_CONSTRUCTORS` | 接口类型的 bean 不自动处理 |
| bean 的全部字段（含父类字段） | 逐字段登记 + `DECLARED_FIELDS` | 字段声明类也会登记 |
| bean 的 init / destroy 方法 | `INVOKE` | 对应 `@Init` / `@PreDestroy` |
| 所有 handler 方法（methodForeach） | 方法 + 参数类型 + 参数泛型 + 返回类型 + 返回泛型 | 见下方"序列化边界" |
| 被代理 bean 的方法（methodEgggs） | 同上 | 代理 bean 的方法会全部登记 |
| `@Inject("${..}")` 注入的配置实体类 | `INVOKE_DECLARED_CONSTRUCTORS` + `INVOKE_PUBLIC_METHODS` | 如 `@Inject("${user}") UserConfig` |
| JDK 代理注入的接口 | 写入 proxy-config.json | 如注入值是 Proxy 实例的接口 |
| JDBC Driver（DriverManager 枚举到的） | `INVOKE_DECLARED_CONSTRUCTORS` | 驱动类会全部登记 |
| `InvocationHandler` | `INVOKE_DECLARED_METHODS` | JDK 动态代理需要 |
| 插件类（plugins 配置中带类名） | 默认构造 | 手动 `registerPlugin` 的除外 |
| 6 个 extend impl 类（存在才注册） | 默认构造 | PropsLoaderExt / PropsConverterExt / AppClassLoaderExt / RuntimeServiceExt / ProxyBinderExt / ActionLoaderFactoryExt |
| 被代理 bean 的 `$$SolonAotProxy` 静态代理类 | 构造器 `(InvocationHandler)` + `INVOKE_DECLARED_CONSTRUCTORS` | 代理类构造时需要反射 |

**注意**：bean 的**成员方法本身**（普通业务方法）不会自动登记，登记的是 handler 方法（映射方法）与代理 bean 的方法。如果你的代码在运行时对普通 bean 的方法做反射调用，需要手动登记。


### 3、自动注册的"资源"（→ resource-config.json）

固定登记 6 个前缀模式：

| 资源模式 | 说明 |
| --- | --- |
| `app.*\.yml` | 应用配置 |
| `app.*\.properties` | 应用配置 |
| `META-INF/.*` | 包内元信息（插件、SPI 等） |
| `WEB-INF/.*` | Web 资源 |
| `static/.*` | 静态资源 |
| `templates/.*` | 模板资源 |

同时，AOT 会按 include 清单**扫描 classpath**，把命中的资源文件路径写入 **solon-resource.json**（排除 `META-INF/maven/`）。native 运行时 `ScanUtil` / `ResourceUtil` 就是从这份清单里找资源的。


### 4、序列化自动注册的边界（重点）

| 场景 | 是否自动注册 | 说明 |
| --- | --- | --- |
| 方法参数类型（非 `java.*` 且实现 Serializable） | 自动 | 通过 handler 方法 / 代理 bean 方法登记时顺带注册 |
| 方法返回值类型（同上） |  自动 | 同上 |
| 方法参数/返回值的泛型实参 |  自动（反射登记） | 泛型信息也会登记 |
| 普通 bean 类（即使实现了 Serializable） |  不自动 | 需要手动 `registerSerialization` |
| lambda 序列化 |  不自动 | 需要手动 `registerLambdaSerialization` |

> 也就是说：**只有"方法参数/返回值"路径上的 Serializable 类才会被自动登记序列化**；其它需要 Java 序列化的类，需要手动补 `metadata.registerSerialization(...)`。


### 5、不自动处理、需要手动登记的内容

| 内容 | 处理方式 |
| --- | --- |
| 第三方框架的反射（类、方法、字段、构造器） | `RuntimeNativeRegistrar` 手动登记（B/C 类第三方） |
| 第三方框架的资源文件 | `registerResourceInclude` 手动登记 |
| 自定义资源路径（如 acme.zip、nginx.conf、banner.txt） | `registerResourceInclude` 手动登记 |
| 一般 bean / 自定义类的 Java 序列化 | `registerSerialization` 手动登记 |
| lambda 序列化 | `registerLambdaSerialization` 手动登记 |
| 动态编译 / 字节码生成（如 CGLIB、ASM 动态代理） | 无法支持，换方案 |
| 运行时才动态加载的类 | 无法探测，需手动登记 |


### 6、如何验证 AOT 是否生效

打包完成后，检查 `target/classes/META-INF/native-image/<应用包路径>/` 目录：

```
native-image.properties     # 默认参数（-H:Class、--no-fallback 等）
reflect-config.json         # 反射登记（应该有你的 bean）
resource-config.json        # 资源登记
serialization-config.json   # 序列化登记（可能为空）
proxy-config.json           # JDK 代理接口（可能为空）
solon-resource.json         # Solon 私有资源索引
```

再检查 `target/generated-sources/` 下是否生成了 `Xxx$$SolonAotProxy.java` 代理源码。两者都在，说明 AOT 处理已生效。


### 7、默认的 native-image 参数

`native-image.properties` 默认写入（可通过 `metadata.registerArg(...)` 追加）：

```
-H:Class=<应用主类>
--report-unsupported-elements-at-runtime
--no-fallback
--install-exit-handlers
```

> `-P native` 还会额外启用 GraalVM 官方可达性元数据仓库（`add-reachability-metadata`），许多自带元数据的第三方库（如 mysql-connector-java 8.x）因此可以直接构建。
