Introduction à JCache

1. Vue d'ensemble

En termes simples, JCache est l'API de mise en cache standard pour Java. Dans ce tutoriel, nous allons voir ce qu'est JCache et comment nous pouvons l'utiliser.

2. Dépendances de Maven

Pour utiliser JCache, nous devons ajouter la dépendance suivante à notre pom.xml :

 javax.cache cache-api 1.0.0-PFD 

Notez que nous pouvons trouver la dernière version de la bibliothèque dans le référentiel central Maven.

Nous devons également ajouter une implémentation de l'API à notre pom.xml ; nous utiliserons Hazelcast ici:

 com.hazelcast hazelcast 3.9-EA 

Nous pouvons également trouver la dernière version de Hazelcast dans son référentiel central Maven.

3. Implémentations JCache

JCache est implémenté par différentes solutions de mise en cache:

  • Implémentation de référence JCache
  • Hazelcast
  • Cohérence Oracle
  • Terre cuite Ehcache
  • Infinispan

Notez que, contrairement aux autres implémentations de référence, il n'est pas recommandé d'utiliser l'implémentation de référence JCache en production car cela provoque des problèmes de concurrence.

4. Principaux composants

4.1. Cache

L' interface Cache propose les méthodes utiles suivantes:

  • get () - prend la clé d'un élément comme paramètre et renvoie la valeur de l'élément; il retourne null si la clé n'existe pas dans le cache
  • getAll () - plusieurs clés peuvent être passées à cette méthode en tant que Set; la méthode renvoie les clés données et les valeurs associées sous forme de Map
  • getAndRemove () - la méthode récupère une valeur à l'aide de sa clé et supprime l'élément du cache
  • put () - insère un nouvel élément dans le cache
  • clear () - supprime tous les éléments du cache
  • containsKey () - vérifie si un cache contient une clé particulière

Comme nous pouvons le voir, les noms des méthodes sont assez explicites. Pour plus d'informations sur ces méthodes et d'autres, visitez le Javadoc.

4.2. CacheManager

CacheManager est l'une des interfaces les plus importantes de l'API. Il nous permet d'établir, de configurer et de fermer des caches .

4.3. CachingProvider

CachingProvider est une interface qui nous permet de créer et de gérer le cycle de vie de CacheManagers .

4.4. Configuration

La configuration est une interface qui nous permet de configurer les caches . Il a une implémentation concrète - MutableConfiguration et une sous- interface - CompleteConfiguration .

5. Création d'un cache

Voyons comment nous pouvons créer un cache simple :

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();

Tout ce que nous faisons est:

  • Création d'un objet CachingProvider , que nous utilisons pour construire un objet CacheManager
  • Création d'un objet MutableConfiguration , qui est une implémentation de l' interface de configuration
  • Création d'un objet Cache à l'aide de l' objet CacheManager que nous avons créé précédemment
  • En mettant toutes les entrées, nous devons mettre en cache dans notre objet Cache
  • Fermeture du CacheManager pour libérer les ressources utilisées par le cache

Si nous ne fournissons aucune implémentation de JCache dans notre pom.xml , l'exception suivante sera levée:

javax.cache.CacheException: No CachingProviders have been configured

La raison en est que la JVM n'a trouvé aucune implémentation concrète de la méthode getCacheManager () .

6. Processeur d'entrée

EntryProcessor nous permet de modifier les entrées du cache à l' aide d'opérations atomiques sans avoir à les rajouter au cache . Pour l'utiliser, nous devons implémenter l' interface EntryProcessor :

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; } }

Maintenant, utilisons notre implémentation EntryProcessor :

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

7. Écouteurs d'événements

Les écouteurs d'événements nous permettent de prendre des mesures lors du déclenchement de l'un des types d'événements définis dans l' énumération EventType , à savoir:

  • ÉTABLI
  • MIS À JOUR
  • SUPPRIMÉ
  • EXPIRÉ

Tout d'abord, nous devons implémenter les interfaces des événements que nous allons utiliser.

Par exemple, si l' on veut utiliser les CREES et les MISES À JOUR types d'événements, nous devons mettre en œuvre les interfaces CacheEntryCreatedListener et CacheEntryUpdatedListener .

Voyons un exemple:

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; } }
     
    

Maintenant, exécutons notre test:

@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 nous permet d'utiliser le mode de lecture directe pour traiter le cache comme le magasin de données principal et en lire les données .

Dans un scénario réel, nous pouvons demander au cache de lire les données du stockage réel.

Jetons un œil à un exemple. Tout d'abord, nous devons implémenter l' interface CacheLoader :

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; } }

Et maintenant, utilisons notre implémentation CacheLoader :

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

Dans ce didacticiel, nous avons vu ce qu'est JCache et exploré certaines de ses fonctionnalités importantes dans quelques scénarios pratiques.

Comme toujours, l'implémentation complète de ce tutoriel peut être trouvée sur GitHub.