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