Files
spring-boot-demo/graalvm-native-images/README.md
T
Claude 8cdfcd4d8d Add graalvm-native-images: Boot 4.1 + GraalVM CE for JDK 25, AOT processing,
the tracing agent, and a real reflection-collision trap

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EQNA6DJ9VgCtW6zhCE8Xud
2026-09-20 11:03:09 +00:00

61 lines
3.0 KiB
Markdown

# GraalVM native images of a Spring Boot 4.1 application
Companion project for [**GraalVM Native Images for Spring Boot 4.1: AOT Processing, the Tracing
Agent, and a Real Reflection Failure**](https://ankurm.com/building-native-images-of-spring-boot-applications-with-graalvm-a-step-by-step-guide/)
on ankurm.com.
A small Spring Boot 4.1 web app, built and run three ways -- a plain `java -jar`, the same jar
with Spring's AOT processing applied, and a GraalVM native image -- with every startup time,
memory number, and failure message in this README and the linked post captured from a real run,
not estimated.
## Versions
| | |
|---|---|
| Spring Boot | 4.1.1 |
| JDK (JVM runs) | Temurin 25.0.4.1 |
| GraalVM (native builds) | GraalVM Community Edition for JDK 25, build 25.0.2+10.1 |
| `native-maven-plugin` | 1.1.8 (pinned by `spring-boot-starter-parent:4.1.1`'s dependency management; 1.1.14 is the latest on Maven Central as of this writing, but the parent's pinned version is what actually runs unless overridden) |
The previous version of this project and its post assumed Spring Boot 3.x, JDK 17, and GraalVM
22.3 -- two major generations behind. See [docs/01-versions-and-setup.md](docs/01-versions-and-setup.md)
for how each version claim here was checked.
## Quickstart
```bash
# 1. Plain JVM run (any JDK 25 build)
mvn -DskipTests package
java -jar target/app.jar
# 2. Native image (needs a GraalVM distribution -- native-image ships bundled, no `gu install` step)
export JAVA_HOME=/path/to/graalvm-25.0.2
mvn -Pnative -DskipTests native:compile # NOT `mvn -Pnative package` -- see docs/02-building-the-image.md
./target/graalvm-native-images
```
## What's in this chapter
| Doc | Covers |
|---|---|
| [01-versions-and-setup.md](docs/01-versions-and-setup.md) | Verified version claims; why `gu install native-image` is obsolete |
| [02-building-the-image.md](docs/02-building-the-image.md) | AOT processing's real generated output; why `-Pnative package` alone does not build a native image |
| [03-the-reflection-trap.md](docs/03-the-reflection-trap.md) | A real `ClassNotFoundException` from a runtime-computed `Class.forName`, the tracing-agent fix, and the metadata-collision trap that fix runs into |
| [04-honest-limits.md](docs/04-honest-limits.md) | What native images cost you, and where Project Leyden fits as the non-full-native alternative |
Every number quoted in the post is in [docs/output/](docs/output) as a trimmed, real transcript.
## Measured, not estimated
| | plain JVM | native image |
|---|---|---|
| Startup ("Started ... in") | 3.472 s | 0.091 s (0.104 s with reflection hints added) |
| RSS at idle | ~190.8 MB | ~105.5 MB |
| Artifact size | 22 MB jar (+ a JDK install) | 93 MB self-contained executable |
| Build time | ordinary `mvn package` | 4m 14s&ndash;4m 19s on 2 vCPU / 8 GB |
Full transcripts: [docs/output/01-jvm-baseline.txt](docs/output/01-jvm-baseline.txt),
[docs/output/02-native-build.txt](docs/output/02-native-build.txt),
[docs/output/05-native-startup-fixed.txt](docs/output/05-native-startup-fixed.txt).