Spring Caching mit Guava Cache

Im vorangegangenen Blogpost haben wir gesehen wie man mit Hilfe von @Cacheable und dem Cache Support von Spring Rückgabewerte von Methoden cachen kann.

Spring liefert in der Core Library zwei Implementationen mit. Den ConcurrentMapCacheManager, der die Daten in einer ConcurrentMap speichert, und den EhCacheCacheManager der im Hintergrund EhCache benutzt. Weiter gibt es noch den NoOpCacheManager. Dieser cacht keine Daten und kann nützlich sein für Tests.

Andere Cache Libraries in das Spring Cache System zu integrieren ist nicht schwer. Eine interessante Cacheimplementation ist in der Google Guava Library enthalten.

Seit Version 10 existiert die Klasse CacheBuilder. Damit lassen sich verschiedenste Arten von Caches erstellen. Der CacheBuilder kann Caches mit einer maximalen Grösse erstellen oder Caches in denen die Einträge nach einer bestimmten Zeit gelöscht werden. Caches können erstellt werden die WeakReferences als Key und/oder Value benutzen. Der Guava Cache speichert, wie der ConcurrentMapCache, die Daten nur lokal im Speicher in einer Virtual Machine ab. Für verteilte und/oder persistente Caches sollte man sich den EhCacheCacheManager genauer ansehen.

Caches lassen sich dank des Builder Patterns sehr einfach erstellen. Hier ein Beispiel eines Caches der maximal 10 Einträge enthalten kann und die Einträge 10 Sekunden nach dem Einfügen wieder löscht.

Werte werden mit put(key, value) eingefügt und mit getIfPresent(key) wieder ausgelesen. Weitere Informationen zum Guava Cache findet man in der Wiki unter http://code.google.com/p/guava-libraries/wiki/CachesExplained.

Um nun den Guava Cache mit dem Spring Cache System zu verheiraten benötigen wir zwei Dinge. Erstens eine Klasse die das Interface org.springframework.cache.Cache implementiert und als Zweites einen CacheManager.

Die Cache Implementation ist ein simpler Wrapper der einen Guava Cache beinhaltet.

Ein Sonderfall der behandelt werden muss ist der null Wert. Der Guava Cache erlaubt keine Werte die null sind, aber es kann durchaus sein das eine @Cacheable Methode null zurückgibt. Um den null Wert auch speichern zu können, wird der Wert in ein Optional Objekt gewrappt. Optional ist auch Bestandteil der Guava Library. Die Methode Optional.fromNullable(obj) gibt entweder eine Optional Instanz zurück, die das Original Objekt umschliesst, oder wenn der Parameter null ist das Objekt Optional.absent(), eine Optional Instanz die kein Objekt wrappt. Mit der Methode optional.orNull() erhalten wir wieder das Original Objekt oder null.

Als CacheManager benutzen wir in diesem Beispiel die Klasse SimpleCacheManager, welche von Spring mitgeliefert wird. Dieser Manager ist für diesen Zweck ausreichend und managt die Namen der Caches zu den tatsächlichen Implementationen.

Das Beispiel erstellt einen Guava Cache mit einer maximalen Grösse von 10 Einträgen und einen zweiten Cache bei dem die Einträge nach einer Minute wieder gelöscht werden. Diese werden mit den Namen “oneMinuteCache” und “maxSizeCache” im CacheManager eingetragen.

Nun können wir sehr einfach die Methoden mit @Cacheable annotieren und den gewünschten Cache spezifizieren.

Beachten muss man bei diesen Caches das Einträge per Default nicht in einem Hintergrundjob aus dem Cache gelöscht werden. Das Cleanup passiert beim Schreiben oder Lesen eines Eeintrages.

Weitere Informationen zu diesem Thema findet man in der Guava Wiki:
http://code.google.com/p/guava-libraries/wiki/CachesExplained#Explicit_Removals

Wie in der Wiki beschrieben, wird das Cleanup bei Caches die sehr selten Werte eintragen in den Leseoperationen durchgeführt und kann dadurch das Lesen verlangsamen. Man kann dies vermeiden, indem ein Hintergrundjob gestartet wird der regelmässig die Methode Cache.cleanUp() aufruft.

Hier ein Beispiel eines Jobs der mit Hilfe von ScheduledExecutorService alle 20 Sekunden die Methode cleanUp() von allen Caches aufruft.

Source Code: https://github.com/ralscha/playground/tree/master/caching/src/main/java/ch/rasc/caching/guava

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">