0
# AOT Optimization and Native Images
1
2
Spring Core provides comprehensive Ahead-of-Time (AOT) compilation support that enables applications to be compiled to native images using GraalVM. This includes runtime hints registration, reflection optimization, and resource bundling for optimal native image performance.
3
4
## AOT Detection and Configuration
5
6
Spring provides utilities to detect when AOT optimizations are available and should be used.
7
8
**AotDetector Utility**
9
```java { .api }
10
public final class AotDetector {
11
public static final String AOT_ENABLED = "spring.aot.enabled";
12
13
public static boolean useGeneratedArtifacts();
14
15
// Private constructor - utility class
16
}
17
```
18
19
**Usage Examples**
20
```java
21
// Check if AOT optimizations should be used
22
boolean shouldUseAot = AotDetector.useGeneratedArtifacts();
23
if (shouldUseAot) {
24
// Use pre-compiled AOT optimizations
25
loadPreCompiledBeans();
26
} else {
27
// Use standard runtime reflection-based initialization
28
loadStandardBeans();
29
}
30
31
// Enable AOT via system property
32
System.setProperty("spring.aot.enabled", "true");
33
34
// Or via environment variable
35
// SPRING_AOT_ENABLED=true
36
37
// Conditional logic based on AOT availability
38
@Component
39
public class ConditionalService {
40
41
public ConditionalService() {
42
if (AotDetector.useGeneratedArtifacts()) {
43
initializeForNativeImage();
44
} else {
45
initializeForJvm();
46
}
47
}
48
}
49
```
50
51
## Runtime Hints System
52
53
The runtime hints system allows applications to register metadata that helps AOT compilation tools understand which classes, methods, fields, and resources need to be available at runtime.
54
55
**RuntimeHints Class**
56
```java { .api }
57
public final class RuntimeHints {
58
public ReflectionHints reflection();
59
public ResourceHints resources();
60
public SerializationHints serialization();
61
public ProxyHints proxies();
62
public JniHints jni();
63
}
64
```
65
66
**RuntimeHintsRegistrar Interface**
67
```java { .api }
68
@FunctionalInterface
69
public interface RuntimeHintsRegistrar {
70
void registerHints(RuntimeHints hints, ClassLoader classLoader);
71
}
72
```
73
74
**Usage Examples**
75
```java
76
// Implement custom runtime hints registrar
77
public class MyApplicationRuntimeHints implements RuntimeHintsRegistrar {
78
79
@Override
80
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
81
// Register reflection hints
82
hints.reflection()
83
.registerType(MyService.class, MemberCategory.INVOKE_PUBLIC_METHODS)
84
.registerType(MyEntity.class, MemberCategory.DECLARED_FIELDS)
85
.registerConstructor(MyController.class.getConstructor(MyService.class), ExecutableMode.INVOKE);
86
87
// Register resource hints
88
hints.resources()
89
.registerPattern("templates/*.html")
90
.registerPattern("static/css/*.css")
91
.registerResourceBundle("messages");
92
93
// Register serialization hints
94
hints.serialization()
95
.registerType(MyDto.class)
96
.registerType(MyResponse.class);
97
98
// Register proxy hints
99
hints.proxies()
100
.registerJdkProxy(MyInterface.class, AnotherInterface.class);
101
}
102
}
103
104
// Register hints programmatically
105
RuntimeHints hints = new RuntimeHints();
106
MyApplicationRuntimeHints registrar = new MyApplicationRuntimeHints();
107
registrar.registerHints(hints, getClass().getClassLoader());
108
```
109
110
## Reflection Hints
111
112
The reflection hints system provides fine-grained control over which classes, methods, fields, and constructors should be available for reflection in native images.
113
114
**ReflectionHints Class**
115
```java { .api }
116
public final class ReflectionHints {
117
// Type registration
118
public Builder registerType(Class<?> type, MemberCategory... memberCategories);
119
public Builder registerType(TypeReference type, MemberCategory... memberCategories);
120
public Builder registerTypeIfPresent(ClassLoader classLoader, String typeName, MemberCategory... memberCategories);
121
122
// Constructor registration
123
public Builder registerConstructor(Constructor<?> constructor, ExecutableMode executableMode);
124
public Builder registerConstructor(TypeReference type, List<TypeReference> parameterTypes, ExecutableMode executableMode);
125
126
// Method registration
127
public Builder registerMethod(Method method, ExecutableMode executableMode);
128
public Builder registerMethod(TypeReference type, String methodName, List<TypeReference> parameterTypes, ExecutableMode executableMode);
129
130
// Field registration
131
public Builder registerField(Field field);
132
public Builder registerField(TypeReference type, String fieldName);
133
134
// Query methods
135
public Stream<TypeHint> typeHints();
136
public TypeHint getTypeHint(Class<?> type);
137
public TypeHint getTypeHint(TypeReference type);
138
}
139
140
public enum MemberCategory {
141
INTROSPECT_PUBLIC_CONSTRUCTORS,
142
INTROSPECT_DECLARED_CONSTRUCTORS,
143
INVOKE_PUBLIC_CONSTRUCTORS,
144
INVOKE_DECLARED_CONSTRUCTORS,
145
INTROSPECT_PUBLIC_METHODS,
146
INTROSPECT_DECLARED_METHODS,
147
INVOKE_PUBLIC_METHODS,
148
INVOKE_DECLARED_METHODS,
149
INTROSPECT_PUBLIC_FIELDS,
150
INTROSPECT_DECLARED_FIELDS,
151
PUBLIC_FIELDS,
152
DECLARED_FIELDS
153
}
154
155
public enum ExecutableMode {
156
INTROSPECT,
157
INVOKE
158
}
159
```
160
161
**Usage Examples**
162
```java
163
// Register comprehensive reflection hints
164
RuntimeHints hints = new RuntimeHints();
165
ReflectionHints reflection = hints.reflection();
166
167
// Register entity classes for full reflection access
168
reflection.registerType(User.class,
169
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
170
MemberCategory.DECLARED_FIELDS,
171
MemberCategory.INVOKE_PUBLIC_METHODS);
172
173
// Register service classes for method invocation
174
reflection.registerType(UserService.class, MemberCategory.INVOKE_PUBLIC_METHODS);
175
176
// Register specific constructors
177
Constructor<UserController> constructor = UserController.class.getConstructor(UserService.class);
178
reflection.registerConstructor(constructor, ExecutableMode.INVOKE);
179
180
// Register specific methods
181
Method findByIdMethod = UserService.class.getMethod("findById", Long.class);
182
reflection.registerMethod(findByIdMethod, ExecutableMode.INVOKE);
183
184
// Register fields for serialization frameworks
185
Field userIdField = User.class.getDeclaredField("id");
186
reflection.registerField(userIdField);
187
188
// Conditional registration based on classpath presence
189
reflection.registerTypeIfPresent(classLoader,
190
"com.fasterxml.jackson.databind.ObjectMapper",
191
MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS,
192
MemberCategory.INVOKE_PUBLIC_METHODS);
193
194
// Register generic types
195
reflection.registerType(TypeReference.of("com.example.GenericService<java.lang.String>"),
196
MemberCategory.INVOKE_PUBLIC_METHODS);
197
198
// Check registered hints
199
TypeHint userHint = reflection.getTypeHint(User.class);
200
if (userHint != null) {
201
boolean hasConstructorHints = !userHint.constructorHints().isEmpty();
202
boolean hasMethodHints = !userHint.methodHints().isEmpty();
203
}
204
```
205
206
## Resource Hints
207
208
Resource hints specify which resources should be bundled into the native image and available at runtime.
209
210
**ResourceHints Class**
211
```java { .api }
212
public final class ResourceHints {
213
// Pattern-based registration
214
public Builder registerPattern(String pattern);
215
public Builder registerPattern(ResourcePatternHint hint);
216
217
// Type-based registration
218
public Builder registerType(Class<?> type);
219
public Builder registerTypeIfPresent(ClassLoader classLoader, String typeName);
220
221
// Resource bundle registration
222
public Builder registerResourceBundle(String baseName);
223
224
// Query methods
225
public Stream<ResourcePatternHint> resourcePatternHints();
226
public Stream<ResourceBundleHint> resourceBundleHints();
227
}
228
229
public final class ResourcePatternHint {
230
public static ResourcePatternHint of(String pattern);
231
public static ResourcePatternHint of(String pattern, Predicate<String> filter);
232
233
public String getPattern();
234
public Predicate<String> getFilter();
235
}
236
```
237
238
**Usage Examples**
239
```java
240
// Register resource patterns
241
RuntimeHints hints = new RuntimeHints();
242
ResourceHints resources = hints.resources();
243
244
// Static web resources
245
resources.registerPattern("static/**")
246
.registerPattern("templates/*.html")
247
.registerPattern("css/*.css")
248
.registerPattern("js/*.js");
249
250
// Configuration files
251
resources.registerPattern("application*.properties")
252
.registerPattern("application*.yml")
253
.registerPattern("config/*.xml");
254
255
// Resource bundles for internationalization
256
resources.registerResourceBundle("messages")
257
.registerResourceBundle("validation")
258
.registerResourceBundle("labels");
259
260
// Class-based resource registration (includes class and related resources)
261
resources.registerType(MyController.class); // Includes MyController.class and package resources
262
resources.registerType(MyService.class);
263
264
// Conditional resource registration
265
resources.registerTypeIfPresent(classLoader, "com.example.OptionalService");
266
267
// Advanced pattern with filtering
268
ResourcePatternHint filteredHint = ResourcePatternHint.of("data/*.json",
269
filename -> !filename.contains("test"));
270
resources.registerPattern(filteredHint);
271
272
// Register resources for specific packages
273
resources.registerPattern("com/example/templates/**")
274
.registerPattern("META-INF/spring/**")
275
.registerPattern("META-INF/services/**");
276
```
277
278
## Serialization Hints
279
280
Serialization hints specify which classes need to be available for serialization/deserialization in native images.
281
282
**SerializationHints Class**
283
```java { .api }
284
public final class SerializationHints {
285
// Type registration
286
public Builder registerType(Class<?> type);
287
public Builder registerType(TypeReference type);
288
public Builder registerTypeIfPresent(ClassLoader classLoader, String typeName);
289
290
// Query methods
291
public Stream<JavaSerializationHint> javaSerializationHints();
292
}
293
```
294
295
**Usage Examples**
296
```java
297
// Register serialization hints
298
RuntimeHints hints = new RuntimeHints();
299
SerializationHints serialization = hints.serialization();
300
301
// Register DTOs and entities for JSON serialization
302
serialization.registerType(UserDto.class)
303
.registerType(OrderDto.class)
304
.registerType(ProductDto.class);
305
306
// Register domain entities
307
serialization.registerType(User.class)
308
.registerType(Order.class)
309
.registerType(Product.class);
310
311
// Register generic types
312
serialization.registerType(TypeReference.of("java.util.List<com.example.UserDto>"))
313
.registerType(TypeReference.of("java.util.Map<java.lang.String, java.lang.Object>"));
314
315
// Conditional registration for optional dependencies
316
serialization.registerTypeIfPresent(classLoader, "com.example.CacheEntry");
317
318
// Register collections and common types
319
serialization.registerType(ArrayList.class)
320
.registerType(HashMap.class)
321
.registerType(LinkedHashMap.class);
322
```
323
324
## Proxy Hints
325
326
Proxy hints specify which interfaces should be available for JDK dynamic proxy creation.
327
328
**ProxyHints Class**
329
```java { .api }
330
public final class ProxyHints {
331
// JDK proxy registration
332
public Builder registerJdkProxy(Class<?>... interfaces);
333
public Builder registerJdkProxy(TypeReference... interfaces);
334
public Builder registerJdkProxy(JdkProxyHint hint);
335
336
// Query methods
337
public Stream<JdkProxyHint> jdkProxyHints();
338
}
339
```
340
341
**Usage Examples**
342
```java
343
// Register proxy hints
344
RuntimeHints hints = new RuntimeHints();
345
ProxyHints proxies = hints.proxies();
346
347
// Register service interfaces for proxy creation
348
proxies.registerJdkProxy(UserService.class)
349
.registerJdkProxy(OrderService.class)
350
.registerJdkProxy(ProductService.class);
351
352
// Register multiple interfaces for single proxy
353
proxies.registerJdkProxy(MyService.class, Serializable.class, Cloneable.class);
354
355
// Register transaction proxies
356
proxies.registerJdkProxy(
357
TypeReference.of("org.springframework.transaction.interceptor.TransactionalProxy"),
358
TypeReference.of("org.springframework.aop.SpringProxy"));
359
360
// Register common Spring proxy interfaces
361
proxies.registerJdkProxy(
362
TypeReference.of("org.springframework.aop.framework.Advised"),
363
TypeReference.of("org.springframework.core.DecoratingProxy"));
364
```
365
366
## Type References
367
368
Type references provide a way to specify types that may not be available on the classpath at compile time.
369
370
**TypeReference Interface**
371
```java { .api }
372
public interface TypeReference {
373
String getName();
374
String getCanonicalName();
375
String getPackageName();
376
String getSimpleName();
377
TypeReference getEnclosingType();
378
379
// Static factory methods
380
static TypeReference of(String name);
381
static TypeReference of(Class<?> type);
382
}
383
```
384
385
**Usage Examples**
386
```java
387
// Create type references for optional dependencies
388
TypeReference optionalType = TypeReference.of("com.example.OptionalService");
389
TypeReference genericType = TypeReference.of("java.util.List<java.lang.String>");
390
TypeReference arrayType = TypeReference.of("[Lcom.example.User;");
391
392
// Use in hints registration
393
RuntimeHints hints = new RuntimeHints();
394
395
hints.reflection()
396
.registerType(optionalType, MemberCategory.INVOKE_PUBLIC_METHODS)
397
.registerType(genericType, MemberCategory.INTROSPECT_PUBLIC_METHODS);
398
399
hints.serialization()
400
.registerType(optionalType);
401
402
// Type reference utilities
403
String packageName = optionalType.getPackageName(); // "com.example"
404
String simpleName = optionalType.getSimpleName(); // "OptionalService"
405
String canonicalName = optionalType.getCanonicalName(); // "com.example.OptionalService"
406
```
407
408
## Native Image Detection
409
410
**NativeDetector Utility**
411
```java { .api }
412
public final class NativeDetector {
413
public static boolean inNativeImage();
414
415
// Private constructor - utility class
416
}
417
```
418
419
**Usage Examples**
420
```java
421
// Runtime behavior adaptation for native images
422
public class AdaptiveService {
423
424
public void initialize() {
425
if (NativeDetector.inNativeImage()) {
426
// Native image optimized initialization
427
initializeForNativeImage();
428
} else {
429
// JVM initialization with full reflection
430
initializeForJvm();
431
}
432
}
433
434
private void initializeForNativeImage() {
435
// Use pre-registered beans and avoid reflection
436
usePrecompiledConfiguration();
437
}
438
439
private void initializeForJvm() {
440
// Use standard Spring reflection-based initialization
441
useReflectionBasedConfiguration();
442
}
443
}
444
445
// Conditional bean creation
446
@Configuration
447
public class ConditionalConfiguration {
448
449
@Bean
450
@ConditionalOnExpression("!T(org.springframework.core.NativeDetector).inNativeImage()")
451
public ReflectionBasedService reflectionService() {
452
return new ReflectionBasedService();
453
}
454
455
@Bean
456
@ConditionalOnExpression("T(org.springframework.core.NativeDetector).inNativeImage()")
457
public PrecompiledService precompiledService() {
458
return new PrecompiledService();
459
}
460
}
461
```
462
463
## Best Practices for AOT Optimization
464
465
**Comprehensive Hints Registration**
466
```java
467
@Component
468
public class ComprehensiveHintsRegistrar implements RuntimeHintsRegistrar {
469
470
@Override
471
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
472
registerReflectionHints(hints);
473
registerResourceHints(hints);
474
registerSerializationHints(hints);
475
registerProxyHints(hints);
476
}
477
478
private void registerReflectionHints(RuntimeHints hints) {
479
// Entity classes need field access for JPA/serialization
480
hints.reflection()
481
.registerType(User.class,
482
MemberCategory.DECLARED_FIELDS,
483
MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS)
484
.registerType(Order.class,
485
MemberCategory.DECLARED_FIELDS,
486
MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS);
487
488
// Service classes need method invocation
489
hints.reflection()
490
.registerType(UserService.class, MemberCategory.INVOKE_PUBLIC_METHODS)
491
.registerType(OrderService.class, MemberCategory.INVOKE_PUBLIC_METHODS);
492
493
// Controllers need full reflection access
494
hints.reflection()
495
.registerType(UserController.class,
496
MemberCategory.INVOKE_PUBLIC_CONSTRUCTORS,
497
MemberCategory.INVOKE_PUBLIC_METHODS,
498
MemberCategory.DECLARED_FIELDS);
499
}
500
501
private void registerResourceHints(RuntimeHints hints) {
502
// Application configuration
503
hints.resources()
504
.registerPattern("application*.properties")
505
.registerPattern("application*.yml")
506
.registerPattern("bootstrap*.properties");
507
508
// Web resources
509
hints.resources()
510
.registerPattern("static/**")
511
.registerPattern("templates/**")
512
.registerPattern("public/**");
513
514
// Message bundles
515
hints.resources()
516
.registerResourceBundle("messages")
517
.registerResourceBundle("ValidationMessages");
518
}
519
520
private void registerSerializationHints(RuntimeHints hints) {
521
// DTOs for JSON serialization
522
hints.serialization()
523
.registerType(UserDto.class)
524
.registerType(OrderDto.class)
525
.registerType(ApiResponse.class);
526
527
// Collection types commonly used in serialization
528
hints.serialization()
529
.registerType(ArrayList.class)
530
.registerType(HashMap.class)
531
.registerType(LinkedHashMap.class);
532
}
533
534
private void registerProxyHints(RuntimeHints hints) {
535
// Service interfaces for AOP proxying
536
hints.proxies()
537
.registerJdkProxy(UserService.class)
538
.registerJdkProxy(OrderService.class);
539
540
// Transaction and caching proxies
541
hints.proxies()
542
.registerJdkProxy(
543
TypeReference.of("org.springframework.transaction.interceptor.TransactionalProxy"),
544
TypeReference.of("org.springframework.aop.SpringProxy"));
545
}
546
}
547
```
548
549
This comprehensive AOT optimization system enables Spring applications to be compiled to efficient native images while maintaining the framework's powerful features and developer experience.