Working with Native Images
1. Understanding GraalVM Native Image
| Aspect | Detail |
|---|---|
| Build | AOT compile JVM bytecode → native ELF/Mach-O |
| Startup | Tens of ms vs seconds |
| Memory | Drastically lower RSS |
| Trade-offs | Long build, no dynamic class loading, peak throughput lower |
2. Adding Native Build Tools Plugin
Example: Add native Maven plugin
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
</plugin>
<!-- Boot starter parent already provides version + AOT plugin -->
3. Configuring Native Image Properties
Example: Configure GraalVM native build arguments
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<configuration>
<buildArgs>
<buildArg>-H:+ReportExceptionStackTraces</buildArg>
<buildArg>--initialize-at-build-time=ch.qos.logback</buildArg>
</buildArgs>
</configuration>
</plugin>
4. Building Native Images (native-image)
Example: Compile and run native image
# With Maven
./mvnw -Pnative native:compile
# Or as a container image (no GraalVM install needed)
./mvnw spring-boot:build-image -Pnative
# Run
./target/orders
5. Handling Reflection Configuration
Example: Register reflection hints
@RegisterReflectionForBinding({UserDto.class, OrderDto.class})
@Configuration
public class NativeHints {}
// Or programmatic
public class MyHints implements RuntimeHintsRegistrar {
@Override public void registerHints(RuntimeHints h, ClassLoader cl) {
h.reflection().registerType(UserDto.class,
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS, MemberCategory.DECLARED_FIELDS);
}
}
6. Configuring Resource Bundles
Example: Register resource and message bundle hints
public class MyHints implements RuntimeHintsRegistrar {
@Override public void registerHints(RuntimeHints h, ClassLoader cl) {
h.resources().registerPattern("config/*.json");
h.resources().registerResourceBundle("messages");
}
}
7. Optimizing Native Image Startup Time
| Technique | Effect |
|---|---|
| PGO (Profile-Guided Optimization) | Higher peak perf |
--initialize-at-build-time |
Move init out of startup |
| Avoid eager bean init | spring.main.lazy-initialization=true |
| G1 GC for native | --gc=G1 (Oracle GraalVM) |
8. Using Native Image with Docker
Example: Native image Dockerfile with distroless
FROM ghcr.io/graalvm/native-image-community:21 AS build
WORKDIR /src
COPY . .
RUN ./mvnw -B -ntp -Pnative native:compile -DskipTests
FROM gcr.io/distroless/base-debian12
COPY --from=build /src/target/orders /app/orders
EXPOSE 8080
ENTRYPOINT ["/app/orders"]
9. Testing Native Images
Example: Run tests in native image
# Run tests inside native image
./mvnw -Pnative test
# Run JVM tests with AOT processing applied
./mvnw -PnativeTest test
10. Troubleshooting Native Image Build Issues
| Symptom | Likely Cause |
|---|---|
| ClassNotFoundException at runtime | Missing reflection hint |
| NoSuchMethodException on proxy | Missing proxy hint |
| Resource not found | Missing resource pattern hint |
| OOM during build | Increase Docker/host memory (8-16GB) |
| Slow build | Normal — minutes per binary; cache layers |
| Tracing agent helper | -agentlib:native-image-agent=... on JVM |