Einführung in JCache

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 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.