Einführung in JCache

1. Übersicht

Einfach ausgedrückt ist JCache die Standard-Caching-API für Java. In diesem Tutorial werden wir sehen, was JCache ist und wie wir es verwenden können.

2. Maven-Abhängigkeiten

Um JCache verwenden zu können, müssen wir unserer pom.xml die folgende Abhängigkeit hinzufügen :

 javax.cache cache-api 1.0.0-PFD 

Beachten Sie, dass wir die neueste Version der Bibliothek im Maven Central Repository finden.

Wir müssen unserer pom.xml auch eine Implementierung der API hinzufügen . Wir werden Hazelcast hier verwenden:

 com.hazelcast hazelcast 3.9-EA 

Die neueste Version von Hazelcast finden Sie auch im Maven Central Repository.

3. JCache-Implementierungen

JCache wird durch verschiedene Caching-Lösungen implementiert:

  • Implementierung der JCache-Referenz
  • Hazelcast
  • Oracle-Kohärenz
  • Terrakotta-Ehcache
  • Infinispan

Beachten Sie, dass im Gegensatz zu anderen Referenzimplementierungen die Verwendung der JCache-Referenzimplementierung in der Produktion nicht empfohlen wird, da dies zu Problemen mit der Parallelität führt.

4. Hauptkomponenten

4.1. Zwischenspeicher

Die Cache- Schnittstelle verfügt über die folgenden nützlichen Methoden:

  • get () - nimmt den Schlüssel eines Elements als Parameter und gibt den Wert des Elements zurück; Es gibt null zurück, wenn der Schlüssel nicht im Cache vorhanden ist
  • getAll () - Mehrere Schlüssel können als Set an diese Methode übergeben werden . Die Methode gibt die angegebenen Schlüssel und zugehörigen Werte als Map zurück
  • getAndRemove () - Die Methode ruft einen Wert mit ihrem Schlüssel ab und entfernt das Element aus dem Cache
  • put () - fügt ein neues Element in den Cache ein
  • clear () - Entfernt alle Elemente im Cache
  • enthältKey () - prüft, ob ein Cache einen bestimmten Schlüssel enthält

Wie wir sehen können, sind die Namen der Methoden ziemlich selbsterklärend. Weitere Informationen zu diesen und anderen Methoden finden Sie im Javadoc.

4.2. CacheManager

CacheManager ist eine der wichtigsten Schnittstellen der API. Es ermöglicht uns, Caches einzurichten , zu konfigurieren und zu schließen .

4.3. CachingProvider

CachingProvider ist eine Schnittstelle, mit der wir den Lebenszyklus von CacheManagern erstellen und verwalten können .

4.4. Aufbau

Die Konfiguration ist eine Schnittstelle, über die wir Caches konfigurieren können . Es gibt eine konkrete Implementierung - MutableConfiguration und eine Subschnittstelle - CompleteConfiguration .

5. Erstellen eines Cache

Mal sehen, wie wir einen einfachen Cache erstellen können :

CachingProvider cachingProvider = Caching.getCachingProvider(); CacheManager cacheManager = cachingProvider.getCacheManager(); MutableConfiguration config = new MutableConfiguration(); Cache cache = cacheManager .createCache("simpleCache", config); cache.put("key1", "value1"); cache.put("key2", "value2"); cacheManager.close();

Wir machen nur:

  • Erstellen eines CachingProvider- Objekts, mit dem wir ein CacheManager- Objekt erstellen
  • Erstellen eines MutableConfiguration Objekt, das eine Implementierung der ist Configuration Interface
  • Erstellen eines Cache- Objekts mit dem zuvor erstellten CacheManager- Objekt
  • Wenn wir alle Einträge einfügen, müssen wir sie in unserem Cache- Objekt zwischenspeichern
  • Schließen des CacheManager , um die vom Cache verwendeten Ressourcen freizugeben

Wenn wir keine Implementierung von JCache in unserer Datei pom.xml bereitstellen , wird die folgende Ausnahme ausgelöst:

javax.cache.CacheException: No CachingProviders have been configured

Der Grund dafür ist, dass die JVM keine konkrete Implementierung der Methode getCacheManager () finden konnte .

6. EntryProcessor

Mit EntryProcessor können wir Cache- Einträge mithilfe atomarer Operationen ändern, ohne sie erneut zum Cache hinzufügen zu müssen . Um es zu verwenden, müssen wir die EntryProcessor- Schnittstelle implementieren :

public class SimpleEntryProcessor implements EntryProcessor, Serializable { public String process(MutableEntry entry, Object... args) throws EntryProcessorException { if (entry.exists()) { String current = entry.getValue(); entry.setValue(current + " - modified"); return current; } return null; } }

Verwenden wir nun unsere EntryProcessor- Implementierung:

@Test public void whenModifyValue_thenCorrect() { this.cache.invoke("key", new SimpleEntryProcessor()); assertEquals("value - modified", cache.get("key")); }

7. Ereignis-Listener

Mit Ereignis-Listenern können wir beim Auslösen eines der in der EventType-Enumeration definierten Ereignistypen folgende Aktionen ausführen :

  • ERSTELLT
  • AKTUALISIERT
  • ENTFERNT
  • ABGELAUFEN

Zuerst müssen wir Schnittstellen der Ereignisse implementieren, die wir verwenden werden.

Zum Beispiel, wenn wir die nutzen möchten ERSTELLT und die AKTUALISIERT Ereignistypen, dann sollten wir die Schnittstellen implementieren CacheEntryCreatedListener und CacheEntryUpdatedListener .

Sehen wir uns ein Beispiel an:

public class SimpleCacheEntryListener implements CacheEntryCreatedListener, CacheEntryUpdatedListener, Serializable { private boolean updated; private boolean created; // standard getters public void onUpdated( Iterable
    
      events) throws CacheEntryListenerException { this.updated = true; } public void onCreated( Iterable
     
       events) throws CacheEntryListenerException { this.created = true; } }
     
    

Lassen Sie uns nun unseren Test durchführen:

@Test public void whenRunEvent_thenCorrect() throws InterruptedException { this.listenerConfiguration = new MutableCacheEntryListenerConfiguration( FactoryBuilder.factoryOf(this.listener), null, false, true); this.cache.registerCacheEntryListener(this.listenerConfiguration); assertEquals(false, this.listener.getCreated()); this.cache.put("key", "value"); assertEquals(true, this.listener.getCreated()); assertEquals(false, this.listener.getUpdated()); this.cache.put("key", "newValue"); assertEquals(true, this.listener.getUpdated()); }

8. CacheLoader

Mit CacheLoader können wir den Durchlesemodus verwenden , um den Cache als Hauptdatenspeicher zu behandeln und Daten daraus zu lesen .

In einem realen Szenario kann der Cache Daten aus dem tatsächlichen Speicher lesen.

Schauen wir uns ein Beispiel an. Zuerst sollten wir die CacheLoader- Schnittstelle implementieren :

public class SimpleCacheLoader implements CacheLoader { public String load(Integer key) throws CacheLoaderException { return "fromCache" + key; } public Map loadAll(Iterable keys) throws CacheLoaderException { Map data = new HashMap(); for (int key : keys) { data.put(key, load(key)); } return data; } }

Und jetzt verwenden wir unsere CacheLoader- Implementierung:

public class CacheLoaderTest { private Cache cache; @Before public void setup() { CachingProvider cachingProvider = Caching.getCachingProvider(); CacheManager cacheManager = cachingProvider.getCacheManager(); MutableConfiguration config = new MutableConfiguration() .setReadThrough(true) .setCacheLoaderFactory(new FactoryBuilder.SingletonFactory( new SimpleCacheLoader())); this.cache = cacheManager.createCache("SimpleCache", config); } @Test public void whenReadingFromStorage_thenCorrect() { for (int i = 1; i < 4; i++) { String value = cache.get(i); assertEquals("fromCache" + i, value); } } }

9. Fazit

In diesem Tutorial haben wir gesehen, was JCache ist, und einige seiner wichtigen Funktionen in einigen praktischen Szenarien untersucht.

Wie immer finden Sie die vollständige Implementierung dieses Tutorials auf GitHub.