Runtime hints til reflection og ressourcer
Registrér hints til reflection, proxyer og ressourcer, så dynamiske funktioner bevares under native-kompilering.
Runtime hints til reflection og ressourcer er en gratis Komplet guide til Spring Boot 4-lektion på CoddyKit. Dette er lektion 2 af 4. Du kan læse alle 3 lektioner i dette læringsspor gratis i deres fulde længde — derefter låser CoddyKit PRO alle lektioner op samt praktiske øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Den er en del af læringsforløbet i Komplet guide til Spring Boot 4, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Komplet guide til Spring Boot 4-kurset indeholder 4 lektioner i alt.
Hvorfor native images ødelægger reflection
GraalVM native-kompilering bruger analyse af en lukket verden: På byggetidspunktet skal den kunne se enhver klasse, metode og felt, der nogensinde kan blive nået. Kodeveje, som den ikke statisk kan bevise er nåbare, fjernes fra den endelige binærfil.
- Reflection (
Class.forName,getDeclaredMethod) skjuler målet for den statiske analyse. - Dynamiske proxyer, der genereres under kørsel, har ingen klasse, som kan scannes på byggetidspunktet.
- Ressourcer, der indlæses via
getResourceAsStream, medtages ikke, medmindre de erklæres.
Løsningen er at give analysatoren eksplicitte metadata kaldet runtime-hints, så den bevarer disse elementer i imaget.
Hvad Spring Boot bidrager med automatisk
Spring Boot 4 og AOT-motoren registrerer allerede hints for de fleste interne framework-elementer: @Component-beans, @ConfigurationProperties-klasser, Jackson-bundne DTO'er, der nås via controllere, samt auto-konfigurationsklasser.
Du skriver kun dine egne hints, når du gør noget, som AOT-motoren ikke kan følge, f.eks.:
- Opretter en klasse via reflection, hvor du indlæser klassens navn fra konfigurationen.
- Serialiserer en type, som ingen controller eller repository refererer til.
- Læser en ressourcefil, der ikke scannes fra classpathen, under kørsel.
- Opretter en dynamisk JDK-proxy til en grænseflade, som du selv har oprettet.
Grænsefladen RuntimeHintsRegistrar
Det primære programmatisk adgangspunkt er RuntimeHintsRegistrar. Du implementerer en enkelt metode, registerHints, som modtager et RuntimeHints-objekt med underregistre til refleksion, ressourcer, proxyer, serialisering og ressourcebundter.
Parameteren ClassLoader gør det muligt kun at registrere betinget, når en type faktisk findes på classpath.
package com.example.demo.hints;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
public class MyRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
// reflection, resources and proxies are registered here
}
}Registrering af refleksionshints
Brug hints.reflection().registerType(...), og angiv de medlemskategorier, du har brug for. Kategorierne er grovkornede kontakter, der fortæller GraalVM, hvilke medlemmer der skal bevares, så de er tilgængelige via refleksion.
INVOKE_DECLARED_CONSTRUCTORS— bevar konstruktører, så de kan kaldes.INVOKE_DECLARED_METHODS— bevar metoder, så de kan kaldes.DECLARED_FIELDS— bevar felter, så de kan læses og skrives.
Giv kun adgang til det, du faktisk bruger; for brede hints gør imaget større.
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
public class ReflectionHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
hints.reflection().registerType(
com.example.demo.PaymentProcessor.class,
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
MemberCategory.INVOKE_DECLARED_METHODS);
}
}Aktivering af hints med @ImportRuntimeHints
En registrar gør ingenting, før Spring får besked på at køre den. Annotér en konfigurations- eller komponentklasse med @ImportRuntimeHints, og angiv din registrar. AOT-motoren kalder den derefter under buildet.
Placér den tæt på den kode, der har brug for hintet, så sammenhængen fortsat er nem at finde.
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportRuntimeHints;
@Configuration
@ImportRuntimeHints(ReflectionHints.class)
public class PaymentConfig {
// beans that rely on reflective access to PaymentProcessor
}Betinget registrering med TypeReference
Hvis en klasse muligvis ikke findes på buildtidspunktet, skal du registrere den ved navn med TypeReference i stedet for en fast .class-literal. Kombinér det med et tilstedeværelsestjek, så hintet kun tilføjes, når typen findes på classpath.
Dette mønster er almindeligt i starterbiblioteker, der tilpasser sig valgfrie afhængigheder.
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.TypeReference;
import org.springframework.util.ClassUtils;
public class OptionalHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
if (ClassUtils.isPresent("com.example.optional.LegacyAdapter", classLoader)) {
hints.reflection().registerType(
TypeReference.of("com.example.optional.LegacyAdapter"),
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);
}
}
}Registrering af ressourcehints
Filer, der indlæses med getResourceAsStream eller ClassPathResource, skal deklareres, ellers forsvinder de fra den native binærfil. Registrér nøjagtige stier eller glob-lignende mønstre gennem hints.resources().
registerPattern("config/*.json")— medtag matchende classpath-ressourcer.registerResource(...)— medtag en enkelt kendtResource.
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
public class ResourceHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
hints.resources()
.registerPattern("templates/email/*.html")
.registerPattern("data/countries.json");
}
}Registrering af proxyhints
JDK-dynamiske proxyer, der oprettes med Proxy.newProxyInstance, skal have alle implementerede grænseflader deklareret, fordi GraalVM skal generere proxyklassen på buildtidspunktet. Brug hints.proxies().registerJdkProxy(...) med hele sættet af grænseflader.
Spring registrerer automatisk proxyer for sine egne @Transactional- og repository-grænseflader; du skal kun tilføje hints for proxyer, du selv opretter.
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
public class ProxyHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
hints.proxies().registerJdkProxy(
com.example.demo.AuditLog.class,
com.example.demo.Versioned.class);
}
}En komplet registrar med flere kategorier
Virkelige registrars kombinerer normalt flere hinttyper. Her deklarerer en enkelt registrar refleksion for en dynamisk indlæst strategi, et ressourcemønster til dens konfiguration og en proxy for en grænseflade, som appen forbinder på kørselstidspunktet.
Når relaterede hints holdes samlet, dokumenterer det præcist, hvilke dynamiske funktioner en funktion afhænger af.
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.TypeReference;
public class StrategyHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
hints.reflection().registerType(
TypeReference.of("com.example.demo.JsonExportStrategy"),
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
MemberCategory.INVOKE_DECLARED_METHODS);
hints.resources().registerPattern("strategies/*.properties");
hints.proxies().registerJdkProxy(
com.example.demo.ExportStrategy.class);
}
}Hinting af serialisering med @RegisterReflectionForBinding
For DTO'er, der kun nås via refleksion (for eksempel gennem en manuelt opbygget ObjectMapper uden for en controller), registrerer den praktiske annotation @RegisterReflectionForBinding alle medlemmer, der kræves til Jackson-binding, på én linje, så du undgår at angive kategorierne manuelt.
Det er en genvej, der i baggrunden delegerer til det samme refleksionsregister.
import org.springframework.aot.hint.annotation.RegisterReflectionForBinding;
import org.springframework.stereotype.Component;
@Component
@RegisterReflectionForBinding({ InvoiceDto.class, LineItemDto.class })
public class InvoiceExporter {
// serializes InvoiceDto with a hand-built ObjectMapper
}Kontrol af hints før native build
Det tager lang tid at kompilere et native image, så kontrollér først hints på JVM'en. GraalVM reachability metadata-agenten registrerer faktisk brug af refleksion og ressourcer under en normal testkørsel og genererer JSON-metadata, som du kan sammenligne med dine hints.
Spring tilbyder også RuntimeHintsPredicates, så du i en enhedstest kan kontrollere, at en bestemt type eller ressource er registreret — hurtig feedback uden et komplet native build.
import org.junit.jupiter.api.Test;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
import static org.assertj.core.api.Assertions.assertThat;
class ReflectionHintsTest {
@Test
void registersPaymentProcessor() {
RuntimeHints hints = new RuntimeHints();
new ReflectionHints().registerHints(hints, getClass().getClassLoader());
assertThat(RuntimeHintsPredicates.reflection()
.onType(com.example.demo.PaymentProcessor.class))
.accepts(hints);
}
}Hurtigt tjek: proxyhints
Din applikation opretter en JDK-dynamisk proxy for to af dine egne grænseflader med Proxy.newProxyInstance. Den fungerer på JVM'en, men kaster en fejl under kørsel i det native image. Hvilket hint løser det?
Opsummering
GraalVM's analyse af den lukkede verden fjerner alt, som den ikke statisk kan bevise er nåbart, så dynamiske funktioner kræver eksplicitte runtime-hints.
- Implementér
RuntimeHintsRegistrar.registerHints, og aktivér den med@ImportRuntimeHints. hints.reflection().registerType(...)med de rigtigeMemberCategory-værdier bevarer refleksionskonstruktører, -metoder og -felter.hints.resources().registerPattern(...)inkluderer filer, der indlæses under kørsel.hints.proxies().registerJdkProxy(...)deklarerer brugerdefinerede JDK-dynamiske proxyer.@RegisterReflectionForBindinger en genvej til DTO'er til serialisering.- Kontrollér med
RuntimeHintsPredicatesog reachability metadata-agenten, før du starter et dyrt native build.
Lær Java med en AI-underviser — gratis
Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.
- Kurser
- 21
- Lektioner
- 84
Ofte stillede spørgsmål
Er lektionen “Runtime hints til reflection og ressourcer” gratis?
Ja — alle 3 lektioner i læringssporet Komplet guide til Spring Boot 4, inklusive “Runtime hints til reflection og ressourcer”, kan læses gratis i deres fulde længde her på webstedet. Derefter låser CoddyKit PRO alle lektioner op samt interaktive øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Komplet guide til Spring Boot 4-kurset indeholder 4 lektioner i alt.
Hvad lærer jeg i “Runtime hints til reflection og ressourcer”?
Registrér hints til reflection, proxyer og ressourcer, så dynamiske funktioner bevares under native-kompilering. Du øver dig i Komplet guide til Spring Boot 4 med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.
Skal jeg have erfaring for at begynde på Komplet guide til Spring Boot 4?
Der kræves ingen tidligere erfaring. Komplet guide til Spring Boot 4 på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 2 af 4.
Hvor lang tid tager lektionen “Runtime hints til reflection og ressourcer”?
De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.
Kan jeg skrive og køre kode i denne Komplet guide til Spring Boot 4-lektion?
Ja. Alle Komplet guide til Spring Boot 4-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.
Alle lektioner i dette kursus
- AOT-behandling og den native build-pipeline
- Runtime hints til reflection og ressourcer
- Class Data Sharing og optimering af JVM-opstart
- Diagnosticering og løsning af problemer med native-kompatibilitet