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
3.3 KiB
02 — AOT processing, and why package alone doesn't build the image
← Previous: 01 — versions and setup | Back to README → | Next: 03 — the reflection trap →
What Spring's AOT processing actually generates
mvn spring-boot:process-aot (bound to the package phase automatically, no profile needed) is
what makes a Spring Boot native image possible at all -- it runs the application's startup logic
once, at build time, and writes down what it learns as plain Java source instead of leaving it to
be rediscovered by reflection at every future startup. On this project it produced, in
target/spring-aot/main/:
- 95 generated
.javasource files -- one*__BeanDefinitions.javaper auto-configuration class and application bean, includingHelloController__BeanDefinitions.javaandReportController__BeanDefinitions.java, plus aGraalvmDemoApplication__ApplicationContextInitializer.javathat builds the wholeApplicationContextas ordinary Java calls instead of classpath scanning. META-INF/native-image/com.ankurm/graalvm-native-images/reachability-metadata.json-- the unified reflection/resource/proxy configuration format GraalVM now uses (a single file, not the older separatereflect-config.json/resource-config.json/proxy-config.jsontrio).native-image.properties-- build arguments the plugin feeds straight tonative-image.
Why mvn -Pnative package alone does not produce a binary
Reflected in this exact setup, not assumed: running mvn -Pnative -DskipTests package completes
in under nine seconds and its log contains add-reachability-metadata, process-aot, jar, and
repackage -- and nothing else. Grepping that log for native-image or Generating ' returns
zero matches. mvn help:effective-pom -Pnative confirms why: the native profile this project
(and a default Spring Initializr project) declares binds no execution of its own to any phase --
it only adds the plugin so its own add-reachability-metadata goal, bound in the plugin's own
metadata, participates in the build. The goal that actually invokes the GraalVM compiler,
native:compile, has to be run explicitly:
mvn -Pnative -DskipTests native:compile
which matches Spring's own current documentation for local (non-Docker) native builds. The
./mvnw clean package -Pnative command in tutorials and in the earlier version of this project's
post does not do this -- confirmed by testing it directly, not by reading the plugin's changelog.
Full transcripts of both runs, side by side:
docs/output/06-package-does-not-compile-native.txt
and docs/output/02-native-build.txt.
The build itself, measured
On this project's 2 vCPU / 8 GB build machine, native-image analysis found 20,126 reachable
types across 29,154 fields and 91,938 methods, registered 7,495 types for reflection, and finished
in 4 minutes 14 seconds to 4 minutes 19 seconds across repeated runs, peaking at 4.36 GB resident
memory during compilation. The resulting executable is 93 MB, versus a 22 MB jar that still needs
a JRE installed alongside it to run at all. Full transcript:
docs/output/02-native-build.txt.