AOT & Native Image
Ahead-of-time processing and GraalVM native images: what AOT generates, the closed-world constraints, reachability hints, build tooling, testing, and the startup and footprint trade-offs. Interviewers ask because 'make it start faster' is a real requirement in serverless and scale-to-zero setups.
part ofSpring Frameworkoverview, primer and where to startread it →on this pageshowhide
explore
- Spring AOT Engine25 questions
- AOT Processing (process-aot)5 questions
- Generated Bean Definitions5 questions
- AOT Processor SPI5 questions
- Build-Time Frozen Conditions5 questions
- AOT Mode on the JVM5 questions
- GraalVM Native Image Fundamentals23 questions
- Closed-World Assumption5 questions
- Reflection Breakage5 questions
- Dynamic Proxy Limits5 questions
- Resources & Serialization4 questions
- Build-Time vs Run-Time Init4 questions
- Reachability Metadata & RuntimeHints31 questions
- RuntimeHintsRegistrar5 questions
- Hint Categories6 questions
- @RegisterReflectionForBinding5 questions
- @ImportRuntimeHints5 questions
- Reachability Metadata Repository5 questions
- @Reflective & ReflectiveProcessor5 questions
- Native Build Tooling24 questions
- native-maven-plugin5 questions
- native-gradle-plugin5 questions
- bootBuildImage Native Buildpack5 questions
- native-image-agent5 questions
- Static Linking & Minimal Base Images4 questions
- AOT & Native Testing18 questions
- AOT-Mode Tests4 questions
- Native Test Execution4 questions
- @DisabledInAotMode5 questions
- RuntimeHintsPredicates5 questions
- Startup, Footprint & JVM Alternatives24 questions
- Startup & Footprint Trade-offs5 questions
- Class Data Sharing (CDS)5 questions
- Project CRaC Checkpoint/Restore4 questions
- Spring CRaC Lifecycle Integration5 questions
- Native Throughput Tuning5 questions
questions
145 · 6 sectionsWhat are the generated `*__BeanDefinitions` source classes that Spring's AOT engine produces at build time, and why are they created?
basics
~20 sDuring an AOT build, Spring generates plain Java classes named like MyService__BeanDefinitions that build each bean's definition in explicit code instead of scanning and reflecting at startup. This lets GraalVM native images work without runtime reflection.
What does it mean that Spring AOT 'freezes' conditions and the bean set at build time?
basics
~20 sDuring an AOT build Spring evaluates all @Conditional/@Profile checks and auto-configuration once, decides which beans exist, and generates code registering exactly those beans. Those decisions are fixed; they are not re-checked when the app runs.
How does Spring discover and register a custom BeanRegistrationAotProcessor or BeanFactoryInitializationAotProcessor?
basics
~10 sTwo ways: list the implementing class in META-INF/spring/aot.factories under the SPI interface name, or register a bean that implements the interface — Spring auto-detects such beans during AOT processing.
What is an instance supplier in AOT-generated bean definitions, and how does it replace reflective bean instantiation?
basics
~20 sAn instance supplier is a callback set on the BeanDefinition (via setInstanceSupplier) that creates the bean by directly calling its constructor or factory method in generated code, instead of Spring reflectively finding and invoking the constructor at runtime.
Why does changing spring.profiles.active at runtime fail to swap beans in an AOT / native Spring Boot app?
basics
~20 sBecause @Profile is a condition. AOT evaluates profiles at build time and bakes in only the beans for the profiles active then. Activating a different profile at runtime cannot add beans that were never generated.
In GraalVM native image, what is the difference between --initialize-at-build-time and --initialize-at-run-time?
basics
~20 s--initialize-at-build-time runs a class's static initializer while the image is being built, baking the resulting state into the binary. --initialize-at-run-time defers it to when the app actually starts, so it runs fresh on each launch.
What is the closed-world assumption in GraalVM native image, and what does it mean for a Spring application?
basics
~20 sGraalVM analyzes your whole app at build time and includes only the code it can prove is reachable. Nothing new can be loaded at runtime, so the native executable is a fixed, self-contained set of classes and methods.
Why are CGLIB (class-based) proxies problematic in a GraalVM native image, and what does Spring prefer instead?
basics
~10 sCGLIB creates proxy classes at runtime by generating new subclasses. A native image is closed at build time and cannot generate classes at runtime, so CGLIB proxies fail. Spring prefers JDK/interface-based proxies instead.
Why does reflection often break when you compile a Spring application to a GraalVM native image?
basics
~20 sGraalVM native image builds a closed world: it only includes code it can see is used at build time. Reflection resolves types/methods at runtime, so unless that reflective access is declared up front, the elements are dropped and calls fail.
In a GraalVM native image, why do classpath resources (like a .txt or .sql file loaded via ClassPathResource) sometimes fail to load at runtime, and what fixes it?
basics
~20 sGraalVM's closed-world build only bundles resources it knows about. Files loaded reflectively at runtime aren't detected, so they're dropped. You must register them (via resource-config.json or Spring ResourceHints) so the build includes them in the image.
What is Spring's RuntimeHints, and what are the main categories of hints it exposes?
basics
~10 sRuntimeHints is a Spring object that records what a native image needs kept at runtime. It groups hints into sub-APIs: reflection, resources, JDK proxies, serialization, and JNI — each feeding a GraalVM config file.
What does the @ImportRuntimeHints annotation do in a Spring application?
basics
~20 s@ImportRuntimeHints is placed on a @Configuration class or bean to register one or more RuntimeHintsRegistrar classes. During AOT/native-image build, Spring calls those registrars so they can declare reflection, resource, and proxy hints the GraalVM compiler needs.
What is the GraalVM reachability-metadata repository and why does a native Spring Boot build need it?
basics
~20 sIt is a community-maintained collection of GraalVM native-image config (reflection, resources, proxies) for popular third-party libraries. The build tool pulls the right config so those libraries work in a native image without you writing hints by hand.
What is a RuntimeHintsRegistrar in Spring, and why do you need one when building a GraalVM native image?
basics
~20 sIt is an interface where you tell the native-image build which classes, resources, or proxies your app uses via reflection. GraalVM closes the world at build time, so anything discovered dynamically must be declared, or it fails at runtime.
How do you register reflection hints with ReflectionHints, and what does MemberCategory control?
basics
~10 sUse hints.reflection().registerType(MyType.class, category...). MemberCategory selects which members become reflectively accessible — e.g. declared constructors, public/declared methods, or fields. It maps to reflect-config.json.
What does the Spring Boot bootBuildImage task do, and how do you make it produce a native-image container?
basics
~10 sbootBuildImage is a Spring Boot build task that packages your app into a Docker/OCI container using Cloud Native Buildpacks. To build a native executable inside it, set the environment variable BP_NATIVE_IMAGE=true for the buildpack.
What is the GraalVM native-build-tools Gradle plugin, and which tasks does it add to a Spring Boot build?
basics
~10 sIt's the Gradle plugin org.graalvm.buildtools.native that lets you compile a GraalVM native image locally. It adds tasks like nativeCompile (build the native executable) and nativeRun (run it).
What is the GraalVM native-maven-plugin and how do you use it to build a native image of a Spring Boot app with Maven?
basics
~10 sIt's the GraalVM native-build-tools Maven plugin that compiles your app into a native executable. In Spring Boot you run mvn -Pnative native:compile; the native profile plus its native:compile goal invoke GraalVM's native-image compiler.
What is the GraalVM native-image-agent and what problem does it solve?
basics
~20 sIt is a JVM agent (enabled with -agentlib:native-image-agent) that watches an app running on the normal JVM and records dynamic behavior like reflection, resource loading and proxies, writing JSON metadata that native-image needs to compile those parts.
Explain how spring-boot process-aot and native:compile are bound in the Maven lifecycle, and why the ordering matters.
basics
~20 sIn the native profile, Spring Boot binds its process-aot goal to run during the build's earlier phases; native:compile (bound around the package phase) runs after it. process-aot generates bean code and reachability hints that native-image needs, so it must run first.
Why are tests using @MockitoBean / @MockBean typically incompatible with AOT mode, and how does @DisabledInAotMode help?
basics
~20 s@MockitoBean and @MockBean replace a real bean with a mock by changing the application context. An AOT-built context is frozen and cannot be changed, so the mock cannot be installed. @DisabledInAotMode skips such tests when running in AOT mode.
You've generated the AOT test artifacts. How do you actually run your tests against the AOT-optimized context on the JVM, and why would you do that instead of building a native image?
basics
~20 sSet the system property spring.aot.enabled=true when running the test task. The TestContext framework then loads the build-time generated context instead of refreshing a fresh one. You do this on the JVM because it's far faster than a native build for catching AOT problems.
Write a test that asserts a registrar registered reflection access to a type's declared constructors.
basics
~10 sRun the registrar against a fresh RuntimeHints, then assert RuntimeHintsPredicates.reflection().onType(MyType.class).withMemberCategory(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS) accepts those hints using AssertJ's .accepts(hints).
What is @DisabledInAotMode and what problem does it solve in Spring tests?
basics
~10 sIt is a Spring test annotation that skips a test when the app runs in AOT (ahead-of-time) mode. You put it on tests whose setup does not work with an AOT-optimized, pre-built application context.
What are AOT-mode tests in Spring, and what does the process-test-aot / processTestAot step actually do?
basics
~20 sAOT (ahead-of-time) test processing pre-builds each test's Spring ApplicationContext at build time instead of at runtime. The processTestAot task (Gradle) or process-test-aot goal (Maven) generates that code so tests can run against a pre-optimized context.
What do you gain by compiling a Spring Boot app to a GraalVM native image instead of running it on the JVM, in terms of startup and memory?
basics
~10 sA native image starts in tens of milliseconds instead of seconds, and uses much less memory (RSS), because the app is compiled ahead-of-time to a native executable with no JVM warm-up.
Walk through the Profile-Guided Optimization (PGO) workflow for a Spring Boot native image. What are the steps and what file is produced?
basics
~10 sThree steps: build an instrumented binary with --pgo-instrument, run it under a realistic workload to produce a profile file (default.iprof), then rebuild passing --pgo=default.iprof so the compiler optimizes the hot paths. Requires Oracle GraalVM.
Why can a warmed-up JVM out-perform a GraalVM native image on peak throughput, and what mitigates that gap?
basics
~20 sThe JVM's JIT compiler profiles running code and re-optimizes hot paths, so after warm-up it can run faster. A native image is compiled once ahead-of-time with no runtime profiling, so its peak throughput is often lower. Profile-Guided Optimization (PGO) narrows the gap.
How do you handle open resources (DB connections, sockets) across a CRaC checkpoint/restore in a Spring app?
basics
~10 sImplement org.crac.Resource: in beforeCheckpoint() close/drain the resource (e.g. evict a connection pool); in afterRestore() re-open it. Register with Core.getGlobalContext().register(this). Spring already does this for its managed Lifecycle beans and many pools support it.
Explain the 'closed-world assumption' of native image and how it constrains a Spring application at build and run time.
basics
~20 sNative image assumes a closed world: every class, reflective call, resource, and proxy that will ever run must be known at build time. Anything discovered dynamically at runtime (unregistered reflection, runtime classpath additions, dynamic proxies) simply isn't there and fails.