Einführung in JCache
1. Überblick
Einfach ausgedrückt istJCache 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 unserenpom.xml die folgende Abhängigkeit hinzufügen:
javax.cache
cache-api
1.0.0-PFD
Beachten Sie, dass wir die neueste Version der Bibliothek inMaven Central Repository finden.
Wir müssen unserenpom.xml auch eine Implementierung der API hinzufügen. Wir werden Hazelcast hier verwenden:
com.hazelcast
hazelcast
3.9-EA
Wir können auch die neueste Version von Hazelcast unterMaven Central Repository finden.
3. JCache-Implementierungen
JCache wird von verschiedenen Caching-Lösungen implementiert:
-
JCache-Referenzimplementierung
-
Hazelcast
-
Oracle-Kohärenz
-
Terracotta Ehcache
-
Infinispan
Beachten Sie, dass im Gegensatz zu anderen Referenzimplementierungenit’s not recommended to use JCache Reference Implementation in production since it causes some concurrency issues.
4. Hauptbestandteile
4.1. Cache
DieCache-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 gibtnull zurück, wenn der Schlüssel inCache nicht vorhanden ist
-
getAll() - Mehrere Schlüssel können alsSet; tan diese Methode übergeben werden. Die Methode gibt die angegebenen Schlüssel und zugehörigen Werte alsMap zurück
-
getAndRemove() - Die Methode ruft einen Wert mit ihrem Schlüssel ab und entfernt das Element ausCache
-
put() - Fügt ein neues Element inCache ein
-
clear() - Entfernt alle Elemente inCache
-
containsKey() - prüft, ob einCache einen bestimmten Schlüssel enthält
Wie wir sehen können, sind die Namen der Methoden so gut wie selbsterklärend. Weitere Informationen zu diesen und anderen Methoden finden Sie unterJavadoc.
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 vonCacheManagers erstellen und verwalten können.
4.4. Configuration
Configuration ist eine Schnittstelle, mit der wirCaches konfigurieren können. Es hat eine konkrete Implementierung -MutableConfiguration und eine Subschnittstelle -CompleteConfiguration.
5. Cache erstellen
Mal sehen, wie wir ein einfachesCache 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 einesCachingProvider-Objekts, mit dem wir einCacheManager-Objekt erstellen
-
Erstellen einesMutableConfiguration-Objekts, bei dem es sich um eine Implementierung derConfiguration-Schnittstelle handelt
-
Erstellen einesCache-Objekts mit dem zuvor erstelltenCacheManager-Objekt
-
Wenn wir alle Einträge einfügen, müssen wir sie in das ObjektCachezwischenspeichern
-
Schließen derCacheManager, um die von denCache verwendeten Ressourcen freizugeben
Wenn wir in unserenpom.xml keine Implementierung von JCache 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 MethodegetCacheManager()finden konnte.
6. EntryProcessor
MitEntryProcessor können wirCache-Einträge mithilfe atomarer Operationen ändern, ohne sie erneut zuCache hinzufügen zu müssen. Um es zu verwenden, müssen wir dieEntryProcessor-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 die Implementierung vonEntryProcessor:
@Test
public void whenModifyValue_thenCorrect() {
this.cache.invoke("key", new SimpleEntryProcessor());
assertEquals("value - modified", cache.get("key"));
}
7. Ereignis-Listener
Event Listeners allow us to take actions beim Auslösen eines der in der AufzählungEventTypedefinierten Ereignistypen:
-
ERSTELLT
-
AKTUALISIERT
-
ENTFERNT
-
ABGELAUFEN
Zunächst müssen wir Schnittstellen der Ereignisse implementieren, die wir verwenden werden.
Wenn wir beispielsweise die EreignistypenCREATED undUPDATED verwenden möchten, sollten wir die SchnittstellenCacheEntryCreatedListener undCacheEntryUpdatedListener implementieren.
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 ausfü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
CacheLoader allowsus to use read-through modeto treat cache as the main data store and read data from it.
In einem realen Szenario kann der Cache Daten aus dem tatsächlichen Speicher lesen.
Schauen wir uns ein Beispiel an. Zuerst sollten wir dieCacheLoader-Schnittstelle implementieren:
public class SimpleCacheLoader
implements CacheLoader {
public String load(Integer key) throws CacheLoaderException {
return "fromCache" + key;
}
public Map loadAll(Iterable extends Integer> keys)
throws CacheLoaderException {
Map data = new HashMap<>();
for (int key : keys) {
data.put(key, load(key));
}
return data;
}
}
Und jetzt verwenden wir die Implementierung vonCacheLoader:
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 inover on GitHub.