Komplett guide til Spring Boot 4 · leksjon

Class Data Sharing og optimalisering av JVM-oppstart

Få raskere oppstart i JVM-modus med CDS, lat initialisering og optimalisering av bean-instansiering.

Leksjon 3 av 413 trinn

Class Data Sharing og optimalisering av JVM-oppstart er en gratis leksjon i Komplett guide til Spring Boot 4 på CoddyKit. Dette er leksjon 3 av 4. Du kan lese valgfritt 3 leksjoner fra denne læringsstien gratis i sin helhet – deretter låser CoddyKit PRO opp alle leksjoner, samt praktisk øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i Komplett guide til Spring Boot 4, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i Komplett guide til Spring Boot 4 inneholder totalt 4 leksjoner.

Hvorfor JVM-oppstart fortsatt er viktig

GraalVM-native-images starter nesten umiddelbart, men de fleste team leverer fortsatt et vanlig JVM-bygg for det store flertallet av distribusjonene. JVM-en er enklere å feilsøke, støtter full refleksjon og fungerer med alle agenter og biblioteker uten ekstra tilpasning.

Den gode nyheten er at en Spring Boot 4-app i JVM-modus ikke trenger å starte tregt. Tre virkemidler har størst effekt:

  • Class Data Sharing (CDS) — hopper over ny parsing av klassemetadata ved hver oppstart.
  • Lazy initialization — oppretter bønner først når de brukes for første gang.
  • Justering av bønneoppretting — unngår kostbart arbeid i konstruktører og ved oppfriskning.

Denne leksjonen går gjennom alle tre i JVM-modus, uten at et native-image kreves.

Hva Class Data Sharing faktisk gjør

Når JVM-en starter, laster den inn, analyserer og verifiserer hundrevis eller tusenvis av klasser. Class Data Sharing (CDS) skriver den analyserte klassegjengivelsen i minnet til en skrivebeskyttet arkivfil én gang, og minnekobler deretter dette arkivet ved hver påfølgende oppstart.

Fordelene er:

  • Mindre arbeid med klasselasting og verifisering ved hver oppstart.
  • Arkivet kan deles mellom flere JVM-prosesser (de samme fysiske minnesidene).

To varianter er relevante for Spring Boot 4:

  • Dynamic CDS (AppCDS) — arkiverer applikasjonsklassene Deres, ikke bare JDK-klassene.
  • Project Leyden / Ahead-of-Time cache — en videreutvikling som bygger på CDS i nyere JDK-er.

Spring Boot 4s innebygde CDS-støtte

Spring Boot har førsteklasses støtte for å generere et AppCDS-arkiv. De kjører appen én gang i en spesiell treningsmodus, den berører applikasjonskonteksten, avslutter og dumper et arkiv. Ved senere kjøringer peker De JVM-en mot dette arkivet.

Treningskjøringen bruker egenskapen nedenfor. Den oppfrisker konteksten og avslutter deretter uten å betjene trafikk:

  • -Dspring.context.exit=onRefresh stopper appen så snart konteksten er klar.
  • JVM-flaggene -XX:ArchiveClassesAtExit fanger opp de innlastede klassene.
# Step 1: training run - refresh context, then exit, dumping the archive
java -XX:ArchiveClassesAtExit=app.jsa \
     -Dspring.context.exit=onRefresh \
     -jar target/myapp.jar

# Step 2: every production start reuses the archive
java -XX:SharedArchiveFile=app.jsa \
     -jar target/myapp.jar

Optimalisering av layout med CDS-venlig JAR

En standard Spring Boot-fat-JAR legger avhengighets-JAR-er inni seg. CDS fungerer best når klassene ligger som vanlige filer på en sti JVM-en kan koble direkte til i minnet. Spring Boots tools-layout pakker ut appen til en katalog, slik at CDS kan indeksere den på en ryddig måte.

Pakk ut den kjørbare strukturen med den innebygde JAR-modusen, og kjør deretter fra den utpakkede layouten:

  • -Djarmode=tools extract skriver en application/-katalog med en flat classpath.
  • Kjøring fra den utpakkede formen gjør både trenings- og produksjonsoppstarter raskere og mer reproduserbare.
# Explode the jar into a CDS-friendly directory structure
java -Djarmode=tools -jar target/myapp.jar extract --destination app

# Train against the exploded app
java -XX:ArchiveClassesAtExit=app/app.jsa \
     -Dspring.context.exit=onRefresh \
     -jar app/myapp.jar

# Production start
java -XX:SharedArchiveFile=app/app.jsa -jar app/myapp.jar

Kontrollere at CDS er aktiv

Bekreft alltid at arkivet faktisk brukes; en skrivefeil i stien fører ubemerket tilbake til ingen CDS. Legg til logging av klasselasting for å se hvilke klasser som kommer fra det delte arkivet, og hvilke som kommer fra den vanlige classpathen.

Bruk det diagnostiske flagget ved en engangskontroll:

  • -Xlog:class+load:file=cds.log merker hver klasse med shared når den lastes fra arkivet.
  • Søk i loggen: Et velfungerende arkiv viser at hoveddelen av rammeverksklassene er merket shared.
# Run with class-load logging and inspect the source of each class
java -XX:SharedArchiveFile=app/app.jsa \
     -Xlog:class+load:file=cds.log \
     -jar app/myapp.jar

# Count how many classes were served from the shared archive
grep -c 'source: shared objects file' cds.log

Lazy oppretting av bønner

Som standard oppretter Spring ivrig alle singleton-bønner under oppfriskningen av konteksten. Med mange bønner dominerer dette arbeidet oppstartstiden. Lazy initialization utsetter opprettelsen av hver bønne til den injiseres eller etterspørres for første gang.

Slå det på globalt med én egenskap:

  • spring.main.lazy-initialization=true gjør alle bønner lazy.
  • Avveining: Feil i en bønnes kobling oppdages når den brukes første gang, ikke ved oppstart, og den første forespørselen som berører en kald bønne, må betale opprettelseskostnaden.

Dette egner seg best for kortvarige CLI-oppgaver og rask oppstart i utvikling; vær forsiktig i tjenester som alltid kjører, der en treg første forespørsel er verre enn en litt tregere oppstart.

spring.main.lazy-initialization=true

Selektiv lazy-oppretting med @Lazy

Global lazy-oppretting er grovkornet. Ofte ønsker De at de fleste bønner skal opprettes ivrig, slik at feil oppdages ved oppstart, men at noen få tunge bønner skal opprettes lazy — for eksempel en klient som åpner en treg forbindelse, eller en hurtigbuffer som forhåndslaster et stort datasett.

Annoter bønnen eller injeksjonspunktet med @Lazy. Spring injiserer da en proxy og oppretter den virkelige bønnen ved det første kallet.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;

@Configuration
public class ReportingConfig {

    // Heavy bean: only built when something actually needs it
    @Bean
    @Lazy
    public ReportGenerator reportGenerator(DataWarehouse warehouse) {
        return new ReportGenerator(warehouse);
    }
}

Hold bønnekonstruktører kostnadseffektive

Den største selvforskyldte oppstartsskaden er å utføre reelt arbeid i konstruktører eller @PostConstruct-metoder: åpne forbindelser, varme opp hurtigbuffere og kalle eksterne tjenester. Alt dette kjøres sekvensielt under oppfriskningen og blokkerer oppstarten.

Tommelfingerregler:

  • Konstruktører skal bare lagre avhengigheter, aldri utføre I/O.
  • Utsett kostbar oppvarming til en hendelse som utløses etter at konteksten er klar, eller kjør den asynkront.
  • Lytt etter ApplicationReadyEvent for oppvarming som ikke skal blokkere oppstarten av konteksten.
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

@Component
public class CacheWarmer {

    private final ProductCache cache;

    public CacheWarmer(ProductCache cache) {
        // cheap: just hold the dependency
        this.cache = cache;
    }

    // Runs after startup, off the critical path
    @Async
    @EventListener(ApplicationReadyEvent.class)
    public void warmUp() {
        cache.preload();
    }
}

Bakgrunnsoppretting av bønner

Spring Boot kan opprette kvalifiserte bønner i et bakgrunnstrådpool mens hovedtråden fortsetter oppfriskningen. Dette parallelliserer uavhengige bønner som tar lang tid å opprette, og reduserer oppstartstiden i klokketid.

Definer en bootstrapExecutor-bønne; Spring bruker den til å opprette bønner som velger dette, i bakgrunnen. Bønner som ikke er avhengige av disse, fortsetter på hovedtråden.

import java.util.concurrent.Executor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@Configuration
public class BootstrapConfig {

    // Spring detects a bean named 'bootstrapExecutor' for background init
    @Bean
    public Executor bootstrapExecutor() {
        ThreadPoolTaskExecutor exec = new ThreadPoolTaskExecutor();
        exec.setCorePoolSize(4);
        exec.setThreadNamePrefix("bg-init-");
        exec.initialize();
        return exec;
    }
}

Måle oppstart med Startup Actuator

Ikke gjett hvor tiden forsvinner — mål. Spring Boot registrerer en oppstartstidslinje for hvert trinn (oppretting av bønner, etterbehandling og autokonfigurasjon) når De oppgir en BufferingApplicationStartup.

Koble den inn i main(), og les deretter de bufrede hendelsene fra endepunktet /actuator/startup for å finne de tregeste trinnene. Sorter etter varighet, og ta først tak i de største tidstyvene.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;

@SpringBootApplication
public class ShopApplication {

    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(ShopApplication.class);
        // capture up to 2048 startup steps for /actuator/startup
        app.setApplicationStartup(new BufferingApplicationStartup(2048));
        app.run(args);
    }
}

Slik settes alt sammen: En oppskrift på optimalisert oppstart

En realistisk optimaliseringsrunde i JVM-modus for en Spring Boot 4-tjeneste kombinerer teknikkene i denne rekkefølgen:

  • 1. Pakk ut JAR-en (jarmode=tools extract), og generer et AppCDS-arkiv med en treningskjøring.
  • 2. Bruk @Lazy på noen få genuint tunge bønner; la resten opprettes ivrig, slik at konfigurasjonsfeil oppdages raskt.
  • 3. Flytt all oppvarming og I/O ut av konstruktørene og inn i lyttere for ApplicationReadyEvent.
  • 4. Legg til en bootstrapExecutor hvis De har flere uavhengige, trege bønner.
  • 5. Bruk BufferingApplicationStartup for å bekrefte at hver endring ga effekt.

Startkommandoen peker deretter ganske enkelt på arkivet:

java -XX:SharedArchiveFile=app/app.jsa \
     -Dspring.threads.virtual.enabled=true \
     -jar app/myapp.jar

Hurtigsjekk: Velge riktig virkemiddel

Du har en Spring Boot 4-nettjeneste som alltid er i drift. Profilering viser at oppstartstiden i hovedsak brukes på å analysere og verifisere rammeverksklasser på nytt ved hver omstart, og at enkelte forespørsler treffer beans som aldri har blitt varmet opp. Du ønsker en raskere gjentakbar oppstart uten risiko for at den første brukerforespørselen blir merkbart treg.

Oppsummering

Spring Boot 4 i JVM-modus kan starte raskt uten å bygges som native. Viktigste punkter:

  • CDS minnekartlegger et forhåndsbehandlet klassearkiv. Opprett det med en treningskjøring (-XX:ArchiveClassesAtExit + spring.context.exit=onRefresh), og bruk det med -XX:SharedArchiveFile. Pakk ut jar-filen først for å få en CDS-vennlig layout.
  • Lazy init utsetter opprettelsen av beans: globalt via spring.main.lazy-initialization, eller målrettet via @Lazy. Dette bytter bort fail-fast og latenstid for den første forespørselen mot raskere oppstart.
  • Justering av beans: Hold konstruktører enkle, flytt oppvarming til ApplicationReadyEvent, og parallelliser uavhengige beans som tar lang tid, med en bootstrapExecutor.
  • Mål alt med BufferingApplicationStartup og /actuator/startup — finjuster de tregeste trinnene, ikke antakelsene dine.
Gratis å komme i gang

Lær deg Java med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
21
Leksjoner
84

Ofte stilte spørsmål

Er leksjonen «Class Data Sharing og optimalisering av JVM-oppstart» gratis?

Ja – du kan lese valgfritt 3 av leksjonene i læringsstien Komplett guide til Spring Boot 4, inkludert «Class Data Sharing og optimalisering av JVM-oppstart», gratis i sin helhet her på nettet. Deretter låser CoddyKit PRO opp alle leksjoner, samt interaktiv øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Kurset i Komplett guide til Spring Boot 4 inneholder totalt 4 leksjoner.

Hva lærer jeg i «Class Data Sharing og optimalisering av JVM-oppstart»?

Få raskere oppstart i JVM-modus med CDS, lat initialisering og optimalisering av bean-instansiering. Du øver på Komplett guide til Spring Boot 4 med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med Komplett guide til Spring Boot 4?

Ingen tidligere erfaring er nødvendig. Komplett guide til Spring Boot 4 på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 3 av 4.

Hvor lang tid tar leksjonen «Class Data Sharing og optimalisering av JVM-oppstart»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne Komplett guide til Spring Boot 4-leksjonen?

Ja. Alle Komplett guide til Spring Boot 4-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. AOT-behandling og den native byggeprosessen
  2. Runtime-hint for refleksjon og ressurser
  3. Class Data Sharing og optimalisering av JVM-oppstart
  4. Diagnostisering og løsning av kompatibilitetsproblemer i native builds
← Tilbake til Komplett guide til Spring Boot 4