Spring Boot 4:n kattava opas · Oppitunti

Class Data Sharing ja JVM:n käynnistyksen optimointi

Nopeuta JVM-tilan käynnistystä CDS:n, lazy initialization -alustuksen ja bean-instansioinnin optimoinnin avulla.

Oppitunti 3/413 vaihetta

Class Data Sharing ja JVM:n käynnistyksen optimointi on ilmainen Spring Boot 4:n kattava opas-oppitunti CoddyKitissä. Tämä on oppitunti 3/4. Voit lukea tästä oppimispolusta kokonaan mitkä tahansa 3 oppituntia ilmaiseksi — sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä käytännön harjoittelun sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Oppitunti kuuluu Spring Boot 4:n kattava opas-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Spring Boot 4:n kattava opas-kurssilla on yhteensä 4 oppituntia.

Miksi JVM:n käynnistys on edelleen tärkeää

GraalVM:n natiivi-imaget käynnistyvät lähes välittömästi, mutta useimmat tiimit toimittavat silti tavallisen JVM-koontiversion valtaosaan käyttöönotoista. JVM:ää on helpompi debugata, se tukee täyttä reflektiota ja toimii kaikkien agenttien ja kirjastojen kanssa suoraan.

Hyvä uutinen on, että JVM-tilassa toimivan Spring Boot 4 -sovelluksen ei tarvitse käynnistyä hitaasti. Kolme keinoa vaikuttavat eniten:

  • Class Data Sharing (CDS) — ohittaa luokkien metatietojen jäsentämisen jokaisella käynnistyskerralla.
  • Laiska alustaminen — luo beanit vasta, kun niitä käytetään ensimmäisen kerran.
  • Beanien luonnin optimointi — välttää raskaan työn konstruktoreissa ja päivityksen aikana.

Tässä oppitunnissa käydään läpi kaikki kolme JVM-tilassa, eikä natiivimagea tarvita.

Mitä Class Data Sharing todella tekee

Kun JVM käynnistyy, se lataa, jäsentää ja tarkistaa satoja tai tuhansia luokkia. Class Data Sharing (CDS) kirjoittaa jäsennetyn, muistissa olevan luokkaesityksen kerran vain luku -tilassa olevaan arkistotiedostoon ja liittää tämän arkiston muistialueeksi jokaisella myöhemmällä käynnistyskerralla.

Hyödyt:

  • Luokkien lataamiseen ja tarkistamiseen kuluu vähemmän aikaa jokaisella käynnistyskerralla.
  • Arkisto voidaan jakaa useiden JVM-prosessien kesken (samat fyysisen muistin sivut).

Spring Boot 4:n kannalta merkityksellisiä on kaksi muotoa:

  • Dynamic CDS (AppCDS) — arkistoi sovelluksen luokat, ei vain JDK:n luokkia.
  • Project Leyden / Ahead-of-Time cache — uudemmissa JDK-versioissa CDS:n päälle rakentuva kehitysaskel.

Spring Boot 4:n sisäänrakennettu CDS-tuki

Spring Boot tukee suoraan AppCDS-arkiston luomista. Sovellus suoritetaan kerran erityisessä koulutustilassa, se käsittelee sovelluskontekstin, lopettaa toimintansa ja tallentaa arkiston. Seuraavilla kerroilla JVM:lle annetaan kyseinen arkisto käytettäväksi.

Koulutusajo käyttää alla olevaa erityisominaisuutta. Se päivittää kontekstin ja sammuu sitten palvelematta liikennettä:

  • -Dspring.context.exit=onRefresh pysäyttää sovelluksen heti kontekstin valmistuttua.
  • JVM:n -XX:ArchiveClassesAtExit-asetuksella tallennetaan ladatut luokat.
# 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

Asettelun optimointi CDS-yhteensopivalla JAR-tiedostolla

Tavallinen Spring Bootin fat JAR sisältää riippuvuuksien JAR-tiedostot sisäkkäin. CDS toimii parhaiten, kun luokat ovat tavallisina tiedostoina polussa, jonka JVM voi suoraan yhdistää muistiin. Spring Bootin tools-asettelu purkaa sovelluksen hakemistoksi, jotta CDS voi indeksoida sen siististi.

Purkaa ajettavan rakenteen sisäänrakennetulla JAR-tilalla ja suorittakaa sovellus sitten puretusta asettelusta:

  • -Djarmode=tools extract kirjoittaa application/-hakemiston, jossa on litteä classpath.
  • Puretusta rakenteesta suorittaminen nopeuttaa sekä koulutus- että tuotantokäynnistyksiä ja tekee niistä toistettavampia.
# 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

CDS:n aktiivisuuden tarkistaminen

Varmistakaa aina, että arkistoa todella käytetään; kirjoitusvirhe polussa johtaa huomaamatta tilanteeseen, jossa CDS ei ole käytössä. Ottakaa käyttöön luokkien latauksen lokitus nähdäksenne, mitkä luokat tulevat jaetusta arkistosta ja mitkä tavallisesta classpathista.

Käyttäkää diagnostista asetusta kertaluonteisen tarkistuksen aikana:

  • -Xlog:class+load:file=cds.log merkitsee jokaisen luokan tunnisteella shared, kun se ladataan arkistosta.
  • Hakekaa lokista: toimivassa arkistossa suurin osa framework-luokista on merkitty tunnisteella 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

Beanien laiska alustaminen

Oletusarvoisesti Spring luo jokaisen singleton-beanin innokkaasti kontekstin päivityksen aikana. Kun beaneja on paljon, tämä työ hallitsee käynnistysaikaa. Laiska alustaminen siirtää kunkin beanin luonnin siihen hetkeen, jolloin sitä ensimmäisen kerran injektoidaan tai pyydetään.

Ottakaa se käyttöön globaalisti yhdellä ominaisuudella:

  • spring.main.lazy-initialization=true tekee kaikista beaneista laiskoja.
  • Haittapuoli: beanin kytkentävirheet tulevat esiin vasta ensimmäisellä käyttökerralla käynnistyksen sijaan, ja ensimmäinen kylmään beaniin osuva pyyntö maksaa sen luonnin hinnan.

Suosikaa tätä lyhytikäisissä CLI-tehtävissä ja kehityksen aikaisessa käynnistyksessä; olkaa varovaisia jatkuvasti käynnissä olevissa palveluissa, joissa hidas ensimmäinen pyyntö on huonompi vaihtoehto kuin hieman hitaampi käynnistys.

spring.main.lazy-initialization=true

Valikoiva laiskuus annotaatiolla @Lazy

Globaali laiskuus on karkea ratkaisu. Usein haluatte useimpien beanien alustuvan innokkaasti, jotta virheet havaitaan käynnistyksen aikana, mutta muutamien raskaiden beanien alustuvan laiskasti — esimerkiksi hitaan yhteyden avaavan clientin tai suuren aineiston esilataavan välimuistin.

Lisätkää @Lazy-annotaatio beaniin tai injektiokohtaan. Spring injektoi tällöin proxyn ja luo todellisen beanin ensimmäisen kutsun yhteydessä.

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);
    }
}

Pidä beanien konstruktorit kevyinä

Suurin itse aiheutettu käynnistysongelma on oikean työn tekeminen konstruktoreissa tai @PostConstruct-metodeissa: yhteyksien avaaminen, välimuistien lämmittäminen ja etäpalvelujen kutsuminen. Kaikki tämä suoritetaan päivityksen aikana peräkkäin, mikä estää käynnistymisen.

Nyrkkisäännöt:

  • Konstruktorien tulisi vain tallentaa riippuvuudet, ei koskaan suorittaa I/O-toimintoja.
  • Siirtäkää kallis lämmitystyö kontekstin valmistumisen jälkeen laukeavaan tapahtumaan tai suorittakaa se asynkronisesti.
  • Kuunnelkaa tapahtumaa ApplicationReadyEvent, kun lämmitys ei saa estää kontekstin käynnistymistä.
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();
    }
}

Beanien luominen taustalla

Spring Boot voi luoda soveltuvat beanit taustasäiepoolissa samalla, kun pääsäie jatkaa päivitystä. Tämä rinnakkaistaa itsenäisten, hitaasti luotavien beanien luonnin ja lyhentää käynnistyksen kokonaisaikaa.

Määritelkää bootstrapExecutor-bean; Spring käyttää sitä taustalla sellaisten beanien luomiseen, jotka ottavat ominaisuuden käyttöön. Beanit, jotka eivät riipu näistä, jatkavat pääsäikeessä.

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;
    }
}

Käynnistyksen mittaaminen Startup Actuatorilla

Älkää arvatko, mihin aika kuluu — mitatkaa se. Spring Boot tallentaa käynnistyksen aikajanan jokaisesta vaiheesta (beanien luominen, jälkikäsittely ja automaattinen konfigurointi), kun käyttöön annetaan BufferingApplicationStartup.

Liittäkää se main()-metodissa ja lukekaa puskuroituneet tapahtumat /actuator/startup-päätepisteestä hitaimpien vaiheiden löytämiseksi. Järjestäkää vaiheet keston mukaan ja korjatkaa ensin eniten aikaa vievät.

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);
    }
}

Kaiken yhdistäminen: optimoidun käynnistyksen ohje

Realistinen JVM-tilassa tehtävä Spring Boot 4 -palvelun optimointi yhdistää tekniikat vaikutusjärjestyksessä:

  • 1. Purkakaa JAR (jarmode=tools extract) ja luokaa AppCDS-arkisto koulutusajolla.
  • 2. Lisätkää @Lazy muutamille aidosti raskaille beaneille; pitäkää muut innokkaasti alustuvina, jotta konfiguraatiovirheet havaitaan nopeasti.
  • 3. Siirtäkää kaikki lämmitys ja I/O pois konstruktoreista ApplicationReadyEvent-kuuntelijoihin.
  • 4. Lisätkää bootstrapExecutor, jos käytössänne on useita toisistaan riippumattomia hitaita beaneja.
  • 5. Varmistakaa BufferingApplicationStartup-luokan avulla, että jokainen muutos paransi tilannetta.

Käynnistyskomennossa tarvitsee tämän jälkeen vain osoittaa arkistoon:

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

Pikatarkistus: oikean keinon valitseminen

Käytössänne on jatkuvasti päällä oleva Spring Boot 4 -verkkopalvelu. Profilointi osoittaa, että käynnistysaikaa hallitsee kehysluokkien jäsentäminen ja tarkistaminen uudelleen jokaisen uudelleenkäynnistyksen yhteydessä, ja muutama pyyntö osuu beaneihin, joita ei ole koskaan esilämmitetty. Haluatte nopeamman toistettavan käynnistyksen ilman riskiä siitä, että ensimmäinen käyttäjäpyyntö hidastuu huomattavasti.

Kertaus

JVM-tilassa toimiva Spring Boot 4 voi käynnistyä nopeasti ilman natiiviksi kääntämistä. Tärkeimmät asiat:

  • CDS kartoittaa valmiiksi jäsennetyn luokka-arkiston muistiin; luokaa se harjoitusajolla (-XX:ArchiveClassesAtExit + spring.context.exit=onRefresh) ja käyttäkää sitä asetuksella -XX:SharedArchiveFile. Purkakaa jar-tiedosto ensin CDS:n kannalta sopivaan rakenteeseen.
  • Laiska alustus siirtää beanien luonnin myöhemmäksi: maailmanlaajuisesti asetuksella spring.main.lazy-initialization tai tarkasti kohdistettuna asetuksella @Lazy. Tämä vaihtaa fail-fast-toiminnan ja ensimmäisen pyynnön viiveen nopeampaan käynnistykseen.
  • Beanien hienosäätö: pitäkää konstruktorit kevyinä, siirtäkää esilämmitys tapahtumaan ApplicationReadyEvent ja suorittakaa toisistaan riippumattomat hitaat beanit rinnakkain käyttämällä bootstrapExecutor-suorittajaa.
  • Mitatkaa kaikki käyttämällä BufferingApplicationStartup-komponenttia ja /actuator/startup-päätepistettä — säätäkää hitaimpia vaiheita, älkää oletuksianne.
Aloita maksutta

Opi Java tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
21
Oppitunnit
84

Usein kysytyt kysymykset

Onko oppitunti ”Class Data Sharing ja JVM:n käynnistyksen optimointi” ilmainen?

Kyllä — voit lukea täällä verkossa kokonaan ilmaiseksi mitkä tahansa Spring Boot 4:n kattava opas-oppimispolun 3 oppituntia, myös oppitunnin “Class Data Sharing ja JVM:n käynnistyksen optimointi”. Sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä interaktiiviset harjoitukset sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Spring Boot 4:n kattava opas-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”Class Data Sharing ja JVM:n käynnistyksen optimointi”?

Nopeuta JVM-tilan käynnistystä CDS:n, lazy initialization -alustuksen ja bean-instansioinnin optimoinnin avulla. Harjoittelet Spring Boot 4:n kattava opas-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni Spring Boot 4:n kattava opas-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin Spring Boot 4:n kattava opas-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 3/4.

Kuinka kauan ”Class Data Sharing ja JVM:n käynnistyksen optimointi”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä Spring Boot 4:n kattava opas-oppitunnilla?

Kyllä. Jokainen Spring Boot 4:n kattava opas-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. AOT-käsittely ja natiivikoontiputki
  2. Reflektion ja resurssien Runtime Hints -vihjeet
  3. Class Data Sharing ja JVM:n käynnistyksen optimointi
  4. Natiiviyhteensopivuusongelmien diagnosointi ja korjaaminen
← Takaisin: Spring Boot 4:n kattava opas