Eine Anleitung zum Caching im Frühjahr

1. Die Cache-Abstraktion?

In diesem Artikel zeigen wir Ihnen , wie Sie die Caching-Abstraktion im Frühjahr verwenden - und generell die Leistung Ihres Systems verbessern.

Wir werden das einfache Caching für einige Beispiele aus der Praxis aktivieren und diskutieren, wie wir die Leistung dieser Aufrufe durch intelligentes Cache-Management praktisch verbessern können.

2. Erste Schritte

Die von Spring bereitgestellte Kern-Caching-Abstraktion befindet sich im Spring-Kontext- Modul. Wenn Sie Maven verwenden, sollte unsere pom.xml die folgende Abhängigkeit enthalten:

 org.springframework spring-context 5.2.8.RELEASE 

Interessanterweise gibt es ein weiteres Modul namens Spring-Context-Support, das sich über dem Spring-Context- Modul befindet und einige weitere CacheManager bereitstellt , die von EhCache oder Caffeine unterstützt werden. Wenn Sie diese als Cache-Speicher verwenden möchten, verwenden Sie stattdessen das Spring-Context-Support- Modul:

 org.springframework spring-context-support 5.2.8.RELEASE 

Da die federkontext Unterstützung Modul transitiv auf das hängt feder Kontext Modul, gibt es keine Notwendigkeit für eine separate Abhängigkeitserklärung für den Frühling-Kontext.

2.1. Frühlingsstiefel

Wenn Sie ein Spring Boot-Benutzer sind, verwenden Sie das Spring-Boot-Starter-Cache- Starterpaket, um die Caching-Abhängigkeiten einfach hinzuzufügen:

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

Unter die Haube bringt der Anlasser das Federkontext- Stützmodul.

3. Aktivieren Sie das Caching

Um das Caching zu aktivieren, verwendet Spring Anmerkungen, ähnlich wie alle anderen Funktionen auf Konfigurationsebene im Framework.

Die Caching-Funktion kann deklarativ aktiviert werden, indem einfach die Annotation @EnableCaching zu einer der Konfigurationsklassen hinzugefügt wird :

@Configuration @EnableCaching public class CachingConfig { @Bean public CacheManager cacheManager() { return new ConcurrentMapCacheManager("addresses"); } }

Sie können die Cache-Verwaltung natürlich auch mit XML- Konfiguration aktivieren :

Hinweis: Nachdem wir das Caching aktiviert haben - für das minimale Setup - müssen wir einen cacheManager registrieren .

3.1. Spring Boot verwenden

Bei Verwendung von Spring Boot würde das bloße Vorhandensein des Starterpakets im Klassenpfad neben der EnableCaching- Annotation denselben ConcurrentMapCacheManager registrieren . Es ist also keine separate Bean-Deklaration erforderlich.

Außerdem können wir den automatisch konfigurierten CacheManager mithilfe einer oder mehrerer CacheManagerCustomizer- Beans anpassen :

@Component public class SimpleCacheCustomizer implements CacheManagerCustomizer { @Override public void customize(ConcurrentMapCacheManager cacheManager) { cacheManager.setCacheNames(asList("users", "transactions")); } }

Die automatische CacheAutoConfiguration -Konfiguration nimmt diese Customizer auf und wendet sie vor ihrer vollständigen Initialisierung auf den aktuellen CacheManager an .

4. Verwenden Sie Caching mit Anmerkungen

Sobald wir das Caching aktiviert haben, besteht der nächste Schritt darin, das Caching-Verhalten mit deklarativen Annotationen an die Methoden zu binden.

4.1. @ Cacheable

Die einfachste Möglichkeit, das Caching-Verhalten für eine Methode zu aktivieren, besteht darin, sie mit @Cacheable abzugrenzen und mit dem Namen des Caches zu parametrisieren, in dem die Ergebnisse gespeichert werden sollen:

@Cacheable("addresses") public String getAddress(Customer customer) {...} 

Der Aufruf von getAddress () überprüft zuerst die Cache- Adressen, bevor die Methode tatsächlich aufgerufen und dann das Ergebnis zwischengespeichert wird.

Während in den meisten Fällen ein Cache ausreicht, unterstützt das Spring-Framework auch mehrere Caches, die als Parameter übergeben werden sollen:

@Cacheable({"addresses", "directory"}) public String getAddress(Customer customer) {...}

In diesem Fall wird das Ergebnis zurückgegeben, wenn einer der Caches das erforderliche Ergebnis enthält, und die Methode wird nicht aufgerufen.

4.2. @ CacheEvict

Was wäre nun das Problem, alle Methoden @Cacheable zu machen ?

Das Problem ist die Größe - wir möchten den Cache nicht mit Werten füllen, die wir nicht oft benötigen . Caches können sehr groß werden, sehr schnell, und wir könnten an vielen veralteten oder nicht verwendeten Daten festhalten.

Die Annotation @CacheEvict wird verwendet, um das Entfernen eines oder mehrerer / aller Werte anzuzeigen, damit neue Werte erneut in den Cache geladen werden können:

@CacheEvict(value="addresses", allEntries=true) public String getAddress(Customer customer) {...}

Hier verwenden wir den zusätzlichen Parameter allEntries in Verbindung mit dem zu entleerenden Cache, um alle Einträge in den Cache- Adressen zu löschen und für neue Daten vorzubereiten.

4.3. @ CachePut

Während @CacheEvict den Aufwand für das Nachschlagen von Einträgen in einem großen Cache reduziert, indem veraltete und nicht verwendete Einträge entfernt werden, möchten Sie im Idealfall vermeiden, zu viele Daten aus dem Cache zu entfernen .

Stattdessen möchten Sie die Einträge bei jeder Änderung selektiv und intelligent aktualisieren.

Mit der Annotation @CachePut können Sie den Inhalt des Caches aktualisieren, ohne die Methodenausführung zu beeinträchtigen. Das heißt, die Methode würde immer ausgeführt und das Ergebnis zwischengespeichert.

@CachePut(value="addresses") public String getAddress(Customer customer) {...}

The difference between @Cacheable and @CachePut is that @Cacheable will skip running the method, whereas @CachePut will actually run the method and then put its results in the cache.

4.4. @Caching

What if you want to use multiple annotations of the same type for caching a method. Look at the incorrect example below:

@CacheEvict("addresses") @CacheEvict(value="directory", key=customer.name) public String getAddress(Customer customer) {...}

The above code would fail to compile since Java does not allow multiple annotations of the same type to be declared for a given method.

The workaround to the above issue would be:

@Caching(evict = { @CacheEvict("addresses"), @CacheEvict(value="directory", key="#customer.name") }) public String getAddress(Customer customer) {...}

As shown in the code snippet above, you can group multiple caching annotations with @Caching, and use it to implement your own customized caching logic.

4.5. @CacheConfig

With the @CacheConfig annotation, you can streamline some of the cache configuration into a single place – at the class level – so that you don't have to declare things multiple times:

@CacheConfig(cacheNames={"addresses"}) public class CustomerDataService { @Cacheable public String getAddress(Customer customer) {...}

5. Conditional Caching

Sometimes, caching might not work well for a method in all situations.

For example – reusing our example from the @CachePut annotation – this will both execute the method as well as cache the results each and every time:

@CachePut(value="addresses") public String getAddress(Customer customer) {...} 

5.1. Condition Parameter

Now – if we want more control over when the annotation is active – @CachePut can be parametrized with a condition parameter that takes a SpEL expression to ensure that the results are cached based on evaluating that expression:

@CachePut(value="addresses", condition="#customer.name=='Tom'") public String getAddress(Customer customer) {...}

5.2. Unless Parameter

We can also control the caching based on the output of the method rather than the input – via the unless parameter:

@CachePut(value="addresses", unless="#result.length()<64") public String getAddress(Customer customer) {...}

The above annotation would cache addresses unless they are shorter than 64 characters.

It's important to know that the condition and unless parameters can be used in conjunction with all the caching annotations.

Diese Art des bedingten Caching kann sich als sehr nützlich erweisen, um große Ergebnisse zu verwalten und das Verhalten basierend auf Eingabeparametern anzupassen, anstatt allen Vorgängen ein generisches Verhalten aufzuzwingen.

6. Deklaratives XML-basiertes Caching

Wenn Sie keinen Zugriff auf den Quellcode Ihrer Anwendung haben oder das Caching-Verhalten extern einfügen möchten, können Sie auch deklaratives XML-basiertes Caching verwenden.

Hier ist unsere XML-Konfiguration:

7. Das Java-basierte Caching

Und hier ist die entsprechende Java-Konfiguration:

@Configuration @EnableCaching public class CachingConfig { @Bean public CacheManager cacheManager() { SimpleCacheManager cacheManager = new SimpleCacheManager(); cacheManager.setCaches(Arrays.asList( new ConcurrentMapCache("directory"), new ConcurrentMapCache("addresses"))); return cacheManager; } }

Und hier ist unser CustomerDataService :

@Component public class CustomerDataService { @Cacheable(value = "addresses", key = "#customer.name") public String getAddress(Customer customer) { return customer.getAddress(); } }

8. Zusammenfassung

In diesem Artikel haben wir die Grundlagen des Caching im Frühjahr und die Verwendung dieser Abstraktion mit Anmerkungen erläutert.

Die vollständige Implementierung dieses Artikels finden Sie im GitHub-Projekt.