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 Maven
Pour utiliser JCache, nous devons ajouter la dépendance suivante à nospom.xml:
javax.cache
cache-api
1.0.0-PFD
Notez que nous pouvons trouver la dernière version de la bibliothèque dans lesMaven Central Repository.
Nous devons également ajouter une implémentation de l'API à nospom.xml; nous utiliserons Hazelcast ici:
com.hazelcast
hazelcast
3.9-EA
On retrouve également la dernière version de Hazelcast à sesMaven Central Repository.
3. Implémentations JCache
JCache est implémenté par diverses 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,it’s not recommended to use JCache Reference Implementation in production since it causes some concurrency issues.
4. Composants principaux
4.1. Cache
L'interfaceCache dispose des méthodes utiles suivantes:
-
get() - prend la clé d'un élément comme paramètre et renvoie la valeur de l'élément; il renvoienull si la clé n'existe pas dans lesCache
-
getAll() - plusieurs clés peuvent être passées à cette méthode en tant que méthodeSet; telle renvoie les clés données et les valeurs associées sous forme deMap
-
getAndRemove() - la méthode récupère une valeur en utilisant sa clé et supprime l'élément desCache
-
put() - insère un nouvel élément dans leCache
-
clear() - supprime tous les éléments dans lesCache
-
containsKey() - vérifie si unCache contient une clé particulière
Comme on peut le constater, les noms des méthodes sont assez explicites. Pour plus d'informations sur ces méthodes et d'autres, visitez le siteJavadoc.
4.2. CacheManager
CacheManager est l'une des interfaces les plus importantes de l'API. Il nous permet d'établir, de configurer et de fermerCaches.
4.3. CachingProvider
CachingProvider est une interface qui nous permet de créer et de gérer le cycle de vie deCacheManagers.
4.4. Configuration
Configuration est une interface qui nous permet de configurerCaches. Il a une implémentation concrète -MutableConfiguration et une sous-interface -CompleteConfiguration.
5. Créer unCache
Voyons comment nous pouvons créer un simpleCache:
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 objetCachingProvider, que nous utilisons pour construire un objetCacheManager
-
Création d'un objetMutableConfiguration, qui est une implémentation de l'interfaceConfiguration
-
Création d'un objetCache à l'aide de l'objetCacheManager que nous avons créé précédemment
-
En mettant toutes les entrées, nous devons mettre en cache dans notre objetCache
-
Fermer lesCacheManager pour libérer les ressources utilisées par lesCache
Si nous ne fournissons aucune implémentation de JCache dans nospom.xml, l'exception suivante sera levée:
javax.cache.CacheException: No CachingProviders have been configured
La raison en est que la machine virtuelle Java n'a trouvé aucune implémentation concrète de la méthodegetCacheManager().
6. EntryProcessor
EntryProcessor nous permet de modifier les entrées deCache en utilisant des opérations atomiques sans avoir à les rajouter auxCache. Pour l'utiliser, nous devons implémenter l'interfaceEntryProcessor:
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émentationEntryProcessor:
@Test
public void whenModifyValue_thenCorrect() {
this.cache.invoke("key", new SimpleEntryProcessor());
assertEquals("value - modified", cache.get("key"));
}
7. Auditeurs de l'événement
Event Listeners allow us to take actions lors du déclenchement de l'un des types d'événements définis dans l'énumérationEventType, qui sont:
-
CRÉÉ
-
MIS À JOUR
-
SUPPRIMÉ
-
EXPIRÉ
Tout d'abord, nous devons implémenter les interfaces des événements que nous allons utiliser.
Par exemple, si nous voulons utiliser les types d'événementsCREATED etUPDATED, alors nous devons implémenter les interfacesCacheEntryCreatedListener etCacheEntryUpdatedListener.
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 allowsus to use read-through modeto treat cache as the main data store and read data from it.
Dans un scénario réel, le cache peut lire les données du stockage réel.
Voyons un exemple. Tout d'abord, nous devons implémenter l'interfaceCacheLoader:
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;
}
}
Et maintenant, utilisons notre implémentationCacheLoader:
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éeover on GitHub.