En guide til caching om foråret

1. Cache-abstraktionen?

I denne artikel skal vi vise, hvordan man gør det brug Caching Abstraction om foråret - og generelt forbedre ydeevnen på dit system.

Vi aktiverer enkel caching for nogle eksempler på virkelige metoder, og vi diskuterer, hvordan vi praktisk kan forbedre udførelsen af ​​disse opkald gennem smart cache-styring.

2. Kom godt i gang

Kernen caching abstraktion leveret af Spring ligger i forårskontekst modul. Så når du bruger Maven, vores pom.xml skal indeholde følgende afhængighed:

 org.springframework spring-context 5.2.8.RELEASE 

Interessant er der et andet modul ved navn spring-context-support, der sidder oven på forårskontekst modul og giver et par flere CacheManagers bakket op af folk som EhCache eller koffein. Hvis du vil bruge dem som din cache-lagring, skal du bruge spring-context-support modul i stedet:

 org.springframework spring-context-support 5.2.8.RELEASE 

Siden den spring-context-support modul afhænger transitivt af forårskontekst modul, er der ikke behov for en separat afhængighedserklæring for forårskontekst.

2.1. Spring Boot

Hvis du bruger Spring Boot, skal du bruge spring-boot-starter-cache startpakke for nemt at tilføje cache-afhængigheder:

 org.springframework.boot spring-boot-starter-cache 2.3.3.RELEASE 

Under emhætten bringer starteren spring-context-support modul.

3. Aktivér caching

For at aktivere caching gør Spring brug af annoteringer, ligesom at aktivere alle andre konfigurationsniveaufunktioner i rammen.

Cachefunktionen kan aktiveres erklærende ved blot at tilføje @EnableCaching kommentar til en af ​​konfigurationsklasserne:

@Configuration @EnableCaching offentlig klasse CachingConfig {@Bean offentlig CacheManager cacheManager () {returner ny ConcurrentMapCacheManager ("adresser"); }}

Du kan selvfølgelig aktiver cacheadministration med XML konfiguration:

Bemærk: Når vi har aktiveret caching - for den minimale opsætning - skal vi registrere en cacheManager.

3.1. Brug af Spring Boot

Når du bruger Spring Boot, er den blotte tilstedeværelse af startpakken på klassestien sammen med EnableCaching kommentar ville registrere det samme ConcurrentMapCacheManager. Så der er ikke behov for en separat bønnedeklaration.

Vi kan også tilpasse den automatisk konfigurerede CacheManager ved hjælp af en eller flere CacheManagerCustomizer bønner:

@Component offentlig klasse SimpleCacheCustomizer implementerer CacheManagerCustomizer {@Override public void customize (ConcurrentMapCacheManager cacheManager) {cacheManager.setCacheNames (asList ("brugere", "transaktioner")); }}

Det CacheAutoConfiguration automatisk konfiguration henter disse tilpasere og anvender dem til den aktuelle CacheManager inden dens fuldstændige initialisering.

4. Brug caching med kommentarer

Når vi har aktiveret caching, er det næste trin at binde cachingadfærden til metoderne med deklarative kommentarer.

4.1. @Cacheable

Den enkleste måde at aktivere cache-opførsel for en metode på er at afgrænse den med @Cacheable og parametriser det med navnet på cachen, hvor resultaterne vil blive gemt:

@Cacheable ("adresser") offentlig String getAddress (kundekunde) {...} 

Det getAddress () opkald vil først kontrollere cachen adresser inden du faktisk påberåber metoden og derefter cachelagrer resultatet.

Mens en cache i de fleste tilfælde er nok, understøtter Spring-rammen også flere cacher, der skal sendes som parametre:

@Cacheable ({"adresser", "bibliotek"}) offentlig String getAddress (kundekunde) {...}

I dette tilfælde, hvis nogen af ​​cacherne indeholder det krævede resultat, returneres resultatet, og metoden påberåbes ikke.

4.2. @CacheEvict

Hvad ville der være problemet med at lave alle metoder @Cacheable?

Problemet er størrelse - vi ønsker ikke at udfylde cachen med værdier, som vi ikke har brug for ofte. Cacher kan vokse ganske store, ganske hurtigt, og vi kan holde fast på mange forældede eller ubrugte data.

Det @CacheEvict annotation bruges til at indikere fjernelse af en eller flere / alle værdier - så nye værdier kan indlæses i cachen igen:

@CacheEvict (værdi = "adresser", allEntries = sand) offentlig String getAddress (kundekunde) {...}

Her bruger vi den ekstra parameter alle indgange i forbindelse med cachen, der skal tømmes - for at rydde alle poster i cachen adresser og forberede det til nye data.

4.3. @CachePut

Mens @CacheEvict reducerer omkostningerne ved at slå poster op i en stor cache ved at fjerne uaktuelle og ubrugte poster, helst du vil undgå at kaste for meget data ud af cachen.

I stedet for vil du selektivt og intelligent opdatere posterne, når de ændres.

Med @CachePut kommentar, kan du opdatere indholdet af cachen uden at forstyrre metoden udførelse. Det vil sige, metoden vil altid blive udført, og resultatet cachet.

@CachePut (værdi = "adresser") offentlig String getAddress (kundekunde) {...}

Forskellen på @Cacheable og @CachePut er det @Cacheable vilje spring over at køre metoden, hvorimod @CachePut vilje faktisk køre metoden og læg derefter resultaterne i cachen.

4.4. @Caching

Hvad hvis du vil bruge flere annoteringer af samme type til cache af en metode. Se på det forkerte eksempel nedenfor:

@CacheEvict ("adresser") @CacheEvict (værdi = "bibliotek", nøgle = kunde.navn) offentlig String getAddress (kundekunde) {...}

Ovenstående kode kunne ikke kompileres, da Java ikke tillader, at flere annoteringer af samme type deklareres for en given metode.

Løsningen til ovenstående problem er:

@Caching (evict = {@CacheEvict ("adresser"), @CacheEvict (værdi = "bibliotek", nøgle = "# kunde.navn")}) offentlig String getAddress (kundekunde) {...}

Som vist i kodestykket ovenfor kan du gruppere flere cache-annoteringer med @Caching, og brug den til at implementere din egen tilpassede cachelogik.

4.5. @CacheConfig

Med @CacheConfig kommentar, du kan strømline noget af cachekonfigurationen til et enkelt sted - på klasseniveau - så du ikke behøver at erklære ting flere gange:

@CacheConfig (cacheNames = {"adresser"}) offentlig klasse CustomerDataService {@Cacheable offentlig String getAddress (kundekunde) {...}

5. Betinget caching

Nogle gange fungerer caching muligvis ikke godt for en metode i alle situationer.

For eksempel - genbrug af vores eksempel fra @CachePut kommentar - dette vil både udføre metoden og cache resultaterne hver gang:

@CachePut (værdi = "adresser") offentlig String getAddress (kundekunde) {...} 

5.1. Tilstandsparameter

Nu - hvis vi ønsker mere kontrol over, hvornår kommentaren er aktiv - @CachePut kan parametriseres med en betingelsesparameter, der tager et SpEL-udtryk for at sikre, at resultaterne caches baseret på evaluering af dette udtryk:

@CachePut (værdi = "adresser", betingelse = "# kunde.navn == 'Tom'") offentlig String getAddress (kundekunde) {...}

5.2. Medmindre parameter

Vi kan også styre cachen baseret på output af metoden snarere end input - via med mindre parameter:

@CachePut (værdi = "adresser", medmindre = "# resultat.længde () <64") offentlig String getAddress (kundekunde) {...}

Ovenstående kommentar cache adresser, medmindre de er kortere end 64 tegn.

Det er vigtigt at vide, at tilstand og med mindre parametre kan bruges sammen med alle cache-annoteringer.

Denne form for betinget cache kan vise sig at være ganske nyttig til styring af store resultater og tilpasning af adfærd baseret på inputparametre i stedet for at håndhæve en generisk adfærd til alle operationer.

6. Deklarativ XML-baseret caching

Hvis du ikke har adgang til din applikations kildekode eller ønsker at indsprøjte caching-opførelsen eksternt, kan du også bruge deklarativ XML-baseret cache.

Her er vores XML-konfiguration:

7. Den Java-baserede caching

Og her er den tilsvarende Java-konfiguration:

@Configuration @EnableCaching offentlig klasse CachingConfig {@Bean offentlig CacheManager cacheManager () {SimpleCacheManager cacheManager = ny SimpleCacheManager (); cacheManager.setCaches (Arrays.asList (ny ConcurrentMapCache ("bibliotek"), ny ConcurrentMapCache ("adresser"))); returner cacheManager; }}

Og her er vores CustomerDataService:

@Komponent offentlig klasse CustomerDataService {@Cacheable (værdi = "adresser", nøgle = "# kunde.navn") offentlig String getAddress (kundekunde) {return customer.getAddress (); }}

8. Resume

I denne artikel diskuterede vi det grundlæggende i Caching om foråret, og hvordan man kan udnytte denne abstraktion godt med annoteringer.

Den fulde implementering af denne artikel kan findes i GitHub-projektet.