mcpField
G
graalvm-native-image

graalvm-native-image

github.com/giuseppe-trisciuoglio开发3653.5k 次安装7 周前更新
代码仓库

关于 graalvm-native-image

指导 Java 开发者将应用构建为 GraalVM Native Image 可执行文件,涵盖构建配置和元数据问题排查。内容包括 Maven、Gradle,以及 Spring Boot、Quarkus 和 Micronaut 的框架配置。

主要功能

  1. 01Maven 与 Gradle 配置指导
  2. 02框架专属的 Native 配置
  3. 03可达性元数据管理
  4. 04迭代式原生构建故障排查
  5. 05可执行文件验证与测量
  6. 06Docker 镜像指导

适用场景

  1. 01将 JVM 应用转换为原生可执行文件
  2. 02缩短部署的冷启动时间
  3. 03排查反射或资源相关构建错误
  4. 04测量原生启动时间与内存用量

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/giuseppe-trisciuoglio/developer-kit --skill graalvm-native-image

安装后在 Claude Code 中输入/graalvm-native-image确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
gradle-native-plugin.md
maven-native-profile.md
quarkus-micronaut-native.md
reflection-resource-config.md
spring-boot-native.md
tracing-agent.md

详细介绍

面向 Java 应用的 GraalVM Native Image

用于借助 GraalVM Native Image 从 Java 应用构建高性能原生可执行文件的专业技能,可大幅缩短启动时间并降低内存消耗。

概述

GraalVM Native Image 通过提前(AOT)编译,将 Java 应用构建为独立的原生可执行文件。这些可执行文件可在毫秒内启动,所需内存显著少于基于 JVM 的部署,适用于无服务器函数、CLI 工具和微服务等对快速启动和低资源占用有严格要求的场景。

此技能提供将 JVM 应用迁移为原生二进制文件的结构化工作流,涵盖构建工具配置、特定框架的模式、反射元数据管理,以及逐步解决原生构建失败的方法。

适用场景

在以下情况下使用此技能:

  • 将基于 JVM 的 Java 应用转换为 GraalVM 原生可执行文件
  • 优化无服务器或容器化部署的冷启动时间
  • 降低 Java 微服务的内存占用(RSS)
  • 使用 GraalVM Native Build Tools 配置 Maven 或 Gradle
  • 解决原生构建中的 ClassNotFoundException、NoSuchMethodException 或资源缺失错误
  • 生成或编辑 reflect-config.json、resource-config.json 或其他 GraalVM 元数据文件
  • 使用 GraalVM 跟踪 Agent 收集可达性元数据
  • 为 Spring Boot 原生支持实现 RuntimeHints
  • 使用 Quarkus 或 Micronaut 构建原生映像

说明

1. 项目上下文分析

在进行任何配置之前,先分析项目以确定构建工具、框架和依赖项:

检测构建工具:

# Check for Maven
if [ -f "pom.xml" ]; then
    echo "Build tool: Maven"
    # Check for Maven wrapper
    [ -f "mvnw" ] && echo "Maven wrapper available"
fi

# Check for Gradle
if [ -f "build.gradle" ] || [ -f "build.gradle.kts" ]; then
    echo "Build tool: Gradle"
    [ -f "build.gradle.kts" ] && echo "Kotlin DSL"
    [ -f "gradlew" ] && echo "Gradle wrapper available"
fi

通过分析依赖项检测框架:

  • Spring Boot:在 pom.xml 或 build.gradle 中查找 spring-boot-starter-*
  • Quarkus:查找 quarkus-* 依赖项
  • Micronaut:查找 micronaut-* 依赖项
  • 纯 Java:未检测到框架依赖项

检查 Java 版本:

java -version 2>&1
# GraalVM Native Image requires Java 17+ (recommended: Java 21+)

识别潜在的原生映像构建难点:

  • 反射密集型库(Jackson、Hibernate、JAXB)
  • 动态代理的使用(JDK 代理、CGLIB)
  • 资源包和类路径资源
  • JNI 或原生库依赖项
  • 序列化要求
2. 构建工具配置

根据检测到的环境配置相应的构建工具插件。

对于 Maven 项目,添加专用的 native 配置文件,以保持标准构建流程整洁。完整配置请参阅 Maven Native Profile Reference。

Maven 基本设置:

<profiles>
  <profile>
    <id>native</id>
    <build>
      <plugins>
        <plugin>
          <groupId>org.graalvm.buildtools</groupId>
          <artifactId>native-maven-plugin</artifactId>
          <version>0.10.6</version>
          <extensions>true</extensions>
          <executions>
            <execution>
              <id>build-native</id>
              <goals>
                <goal>compile-no-fork</goal>
              </goals>
              <phase>package</phase>
            </execution>
          </executions>
          <configuration>
            <imageName>${project.artifactId}</imageName>
            <buildArgs>
              <buildArg>--no-fallback</buildArg>
            </buildArgs>
          </configuration>
        </plugin>
      </plugins>
    </build>
  </profile>
</profiles>

使用以下命令构建:./mvnw -Pnative package

对于 Gradle 项目,应用 org.graalvm.buildtools.native 插件。完整配置请参阅 Gradle Native Plugin Reference。

Gradle 基本设置(Kotlin DSL):

plugins {
    id("org.graalvm.buildtools.native") version "0.10.6"
}

graalvmNative {
    binaries {
        named("main") {
            imageName.set(project.name)
            buildArgs.add("--no-fallback")
        }
    }
}

使用以下命令构建:./gradlew nativeCompile

3. 特定框架的配置

每个框架都有自己的 AOT 策略。根据检测到的框架应用正确的配置。

Spring Boot(3.x+):Spring Boot 内置了 GraalVM 支持和 AOT 处理。有关 RuntimeHints、@RegisterReflectionForBinding 和测试支持等模式,请参阅 Spring Boot Native Reference。

要点:

  • 使用包含原生配置文件的 spring-boot-starter-parent 3.x+
  • 通过 RuntimeHintsRegistrar 注册反射提示
  • 使用 process-aot 目标运行 AOT 处理
  • 使用以下命令构建:./mvnw -Pnative native:compile 或 ./gradlew nativeCompile

Quarkus 和 Micronaut:这些框架从设计之初就优先支持原生构建,所需的额外配置很少。请参阅 Quarkus & Micronaut Reference。

4. GraalVM 可达性元数据

Native Image 采用封闭世界假设——所有代码路径都必须在构建时已知。反射、资源和代理等动态功能需要显式配置元数据。

元数据文件放置在 META-INF/native-image/<group.id>/<artifact.id>/:

文件用途
reachability-metadata.json统一元数据(反射、资源、JNI、代理、资源包、序列化)
reflect-config.json旧版:反射注册
resource-config.json旧版:资源包含模式
proxy-config.json旧版:动态代理接口
serialization-config.json旧版:序列化注册
jni-config.json旧版:JNI 访问注册

完整格式和示例请参阅反射与资源配置参考。

5. 迭代式修复引擎

Native Image 构建经常会因缺少元数据而失败。请按照以下迭代方法操作:

步骤 1 — 执行 Native Image 构建:

# Maven
./mvnw -Pnative package 2>&1 | tee native-build.log

# Gradle
./gradlew nativeCompile 2>&1 | tee native-build.log

步骤 2 — 解析构建错误并找出根本原因:

常见错误模式及其修复方法:

错误模式原因修复方法
ClassNotFoundException: com.example.MyClass缺少反射元数据添加到 reflect-config.json,或使用 @RegisterReflectionForBinding
NoSuchMethodException方法未注册用于反射将方法添加到反射配置中
MissingResourceException资源未包含在 Native Image 中添加到 resource-config.json
Proxy class not found动态代理未注册将接口列表添加到 proxy-config.json
UnsupportedFeatureException: Serialization缺少序列化元数据添加到 serialization-config.json

步骤 3 — 应用修复,更新相应的元数据文件或使用框架注解。

步骤 4 — 重新构建并验证。 重复上述步骤,直到构建成功。

步骤 5 — 如果手动修复仍不够,使用 GraalVM 跟踪 Agent 自动收集可达性元数据。请参阅跟踪 Agent 参考。

6. 验证与基准测试

Native Image 构建成功后:

验证可执行文件能否正常运行:

# Run the native executable
./target/<app-name>

# For Spring Boot, verify the application context loads
curl http://localhost:8080/actuator/health

测量启动时间:

# Time the startup
time ./target/<app-name>

# For Spring Boot, check the startup log
./target/<app-name> 2>&1 | grep "Started .* in"

测量内存占用(RSS):

# On Linux
ps -o rss,vsz,comm -p $(pgrep <app-name>)

# On macOS
ps -o rss,vsz,comm -p $(pgrep <app-name>)

与 JVM 基准进行比较:

指标JVMNative改进
启动时间~2-5s~50-200ms10-100x
内存(RSS)~200-500MB~30-80MB3-10x
二进制文件大小JRE + JARs单个二进制文件更精简
7. Docker 集成

使用 Native 可执行文件构建精简容器镜像:

# Multi-stage build
FROM ghcr.io/graalvm/native-image-community:21 AS builder
WORKDIR /app
COPY . .
RUN ./mvnw -Pnative package -DskipTests

# Minimal runtime image
FROM debian:bookworm-slim
COPY --from=builder /app/target/<app-name> /app/<app-name>
EXPOSE 8080
ENTRYPOINT ["/app/<app-name>"]

对于 Spring Boot 应用,请使用 paketobuildpacks/builder-jammy-tiny 和 Cloud Native Buildpacks:

./mvnw -Pnative spring-boot:build-image

最佳实践

  1. 对于复杂项目,先使用跟踪 Agent生成初始元数据基线
  2. 使用 native 配置文件,将 Native 专用配置与标准构建分开
  3. 优先使用 --no-fallback,确保进行真正的 Native 构建(不回退到 JVM)
  4. 使用 nativeTest 在 Native 模式下运行 JUnit 测试
  5. 使用 GraalVM Reachability Metadata Repository 获取第三方库元数据
  6. 尽量减少反射——尽可能优先使用构造函数注入和编译时 DI
  7. 显式包含资源模式,而不是依赖类路径扫描
  8. 前后进行性能分析——始终测量启动和内存方面的改进
  9. 使用 Java 21+,以获得最佳的 GraalVM 兼容性和性能
  10. 确保 GraalVM 和 Native Build Tools 的版本一致

示例

示例 1:为 Spring Boot Maven 项目添加原生支持

场景: 你有一个 Spring Boot 3.x REST API,并希望将其编译为原生可执行文件。

步骤 1 — 在 pom.xml 中添加原生配置文件:

<profiles>
  <profile>
    <id>native</id>
    <build>
      <plugins>
        <plugin>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-maven-plugin</artifactId>
          <executions>
            <execution>
              <id>process-aot</id>
              <goals>
                <goal>process-aot</goal>
              </goals>
            </execution>
          </executions>
        </plugin>
        <plugin>
          <groupId>org.graalvm.buildtools</groupId>
          <artifactId>native-maven-plugin</artifactId>
        </plugin>
      </plugins>
    </build>
  </profile>
</profiles>

步骤 2 — 为 DTO 注册反射提示:

@RestController
@RegisterReflectionForBinding({UserDto.class, OrderDto.class})
public class UserController {

    @GetMapping("/users/{id}")
    public UserDto getUser(@PathVariable Long id) {
        return userService.findById(id);
    }
}

步骤 3 — 构建并运行:

./mvnw -Pnative native:compile
./target/myapp
# Started MyApplication in 0.089 seconds
示例 2:解决原生构建中的反射错误

场景: 原生构建因 Jackson 序列化的 DTO 而失败,并报错 ClassNotFoundException。

错误输出:

com.oracle.svm.core.jdk.UnsupportedFeatureError:
  Reflection registration missing for class com.example.dto.PaymentResponse

修复 — 添加到 src/main/resources/META-INF/native-image/reachability-metadata.json:

{
  "reflection": [
    {
      "type": "com.example.dto.PaymentResponse",
      "allDeclaredConstructors": true,
      "allDeclaredMethods": true,
      "allDeclaredFields": true
    }
  ]
}

或者使用 Spring Boot 注解方式:

@RegisterReflectionForBinding(PaymentResponse.class)
@Service
public class PaymentService { /* ... */ }
示例 3:在复杂项目中使用跟踪 Agent

场景: 包含许多第三方库的项目需要全面的可达性元数据。

# 1. Build the JAR
./mvnw package -DskipTests

# 2. Run with the tracing agent
java -agentlib:native-image-agent=config-output-dir=src/main/resources/META-INF/native-image \
    -jar target/myapp.jar

# 3. Exercise all endpoints
curl http://localhost:8080/api/users
curl -X POST http://localhost:8080/api/orders -H 'Content-Type: application/json' -d '{"item":"test"}'
curl http://localhost:8080/actuator/health

# 4. Stop the application (Ctrl+C), then build native
./mvnw -Pnative native:compile

# 5. Verify
./target/myapp

限制与警告

关键限制
  • GraalVM Native Image 要求 Java 17+(为获得最佳兼容性,建议使用 Java 21+)
  • 封闭世界假设:所有代码路径都必须在构建时已知——动态类加载、运行时字节码生成和 MethodHandles.Lookup 可能无法使用
  • 构建时间和内存:原生编译非常消耗资源——典型项目预计需要 2-10 分钟和 4-8 GB RAM
  • 并非所有库都兼容:严重依赖反射、动态代理或 CGLIB 的库可能需要大量元数据配置
  • AOT 配置文件在构建时固定:Spring Boot @Profile 和 @ConditionalOnProperty 在 AOT 处理期间求值,而不是在运行时
常见陷阱
  • 忘记添加 --no-fallback:没有此标志,构建可能会悄悄生成 JVM 回退映像,而不是真正的原生可执行文件
  • 跟踪 Agent 覆盖不完整:Agent 只会捕获运行期间执行过的代码路径——确保所有功能都经过测试
  • 版本不匹配:保持 GraalVM JDK、Native Build Tools 插件和框架版本一致,以避免不兼容
  • 类路径差异:AOT/构建时的类路径必须与运行时一致——原生编译后添加或移除 JAR 会导致失败
安全注意事项
  • 原生可执行文件比 JAR 更难反编译,但并非无法篡改
  • 确保构建时不会将机密嵌入原生映像
  • 对敏感数据使用环境变量或外部配置

故障排除

问题解决方案
构建时内存不足增加构建内存:在 buildArgs 中使用 -J-Xmx8g
构建耗时过长使用构建缓存、缩减类路径,并为开发启用快速构建模式
应用在运行时崩溃缺少反射/资源元数据——运行跟踪 Agent
Spring Boot 上下文加载失败检查 @Conditional Bean 和依赖配置文件的配置
第三方库不兼容查看 GraalVM Reachability Metadata 仓库,或手动添加提示

评论

支持 Markdown