Développement applicatif Développement applicatif Java

Hello world : Ehcache chapter !

Publié le 06/01/2021 Par Soufiane ZENIOU

Vous l’avez peut-être remarqué, le nom Ehcache est un palindrome. Reconnu pour sa facilité d’intégration, il offre de nombreuses fonctionnalités intéressantes…

Vous l’avez peut-être remarqué, le nom Ehcache est un palindrome. Reconnu pour sa facilité d’intégration, il offre de nombreuses fonctionnalités intéressantes par rapport aux collections habituelles comme la persistance du cache sur le disque, notamment lors du redémarrage de la VM par exemple, de la configuration de l’expiration des données du cache et des ‘‘listenerers’’ pour les éventements du cache.

À l’heure de l’écriture de cet article, il existe deux versions majeures d’Ehcache : Ehcache 2.X et Ehcache 3.X. Dans la suite de cet article, nous allons utiliser la version 3.X, qui est d’ailleurs recommandée et qui fournit l’implémentation de la spécification JSR-107*.

I/ Dépendance Maven 

Dans le pom,xml du projet, ajoutez la dépendance suivante pour intégrer ehcache :

<dependency>
 <groupId>org.ehcache</groupId>
 <artifactId>ehcache</artifactId>
 <version>3.8.1</version>
</dependency>

PS : la version 3.x d’Ehcache nécessite la JDK 8 ou +.

II/ Création du cache

Il existe deux façons de créer et de configurer un cache Ehcache :

  1. La configuration xml, avec la définition du fichier que l’on retrouve ici.
  2. La configuration en POJO via l’API d’Ehcache.

Dans cet article, nous allons aborder la deuxième méthode.

a)    Méthodologie de création

Il est assez simple de créer le cache :

public static Cache createInMemoryCache(String cacheName, Class<?> ketType, Class<?> valueType){
 CacheConfigurationBuilder<?, ?> configurationBuilder = CacheConfigurationBuilder
 .newCacheConfigurationBuilder(ketType, valueType, ResourcePoolsBuilder.heap(100));
 CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
 .withCache(cacheName, configurationBuilder)
 .build(true);
 
 return cacheManager.getCache(cacheName, ketType, valueType);
}
  • On crée une instance du CacheManagerBuilder.
  • On utilise cette instance pour créer le cache nommé avec le nom fourni en paramètre.
  • Et avec l’instance créée par le CacheConfigurationBuilder, on spécifie le type de la clé et le type de la valeur associée ainsi que la capacité du cache à 100 entrées.
  • À la fin, la méthode build() est invoquée avec le paramètre « true » pour demander l’initialisation du cache. Ce code est équivalent à celui-là :
public static Cache createInMemoryCache(String cacheName, Class<?> ketType, Class<?> valueType){
 CacheConfigurationBuilder<?, ?> configurationBuilder = CacheConfigurationBuilder
 .newCacheConfigurationBuilder(ketType, valueType, ResourcePoolsBuilder.heap(100));
 CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
 .withCache(cacheName, configurationBuilder)
 .build();
 cacheManager.init();
 return cacheManager.getCache(cacheName, ketType, valueType);
}

Test du cache

@Test
public void GivenCache_WhenAccessWithKey_ThenGetTheValue(){
 Cache inMemoryCache = CacheHelper.createInMemoryCache("inMemoryCache", Integer.class, String.class);
 Integer key = 1;
 String value = "Meritis";
 assertFalse(inMemoryCache.containsKey(key));
 inMemoryCache.put(key, value);
 assertTrue(value.equals(inMemoryCache.get(key)));

}

Dans ce test simple, on a créé un cache nommé « inMemoryCache » qui map un entier à une String. Puis, nous avons testé au début que le cache ne contient pas la clé 1. Ensuite, nous avons inséré cette clé avec la valeur « Meritis » et, au final, nous avons pu vérifier que cette valeur remonte bien du cache.

b)    Quelques fonctionnalités d’Ehcahe

  • Cache avec un délai d’expiration des données

Le cache que nous avons vu précédemment garde en mémoire les données pendant toute la durée de vie de la JVM. Si vous avez besoin de virer ces données après un certain temps, voici comment faire :

public static Cache createExpiryEnabledInMemoryCache(String cacheName, Class<?> ketType, Class<?> valueType, int expiryPeriod){
 CacheConfigurationBuilder<?, ?> cacheConfigurationBuilder = CacheConfigurationBuilder
 .newCacheConfigurationBuilder(ketType, valueType, ResourcePoolsBuilder.heap(100))
 .withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(expiryPeriod)));
 CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
 .withCache(cacheName, cacheConfigurationBuilder)
 .build(true);

 return cacheManager.getCache(cacheName, ketType, valueType);
}

Par rapport à la configuration précédente, nous avons ajouté withExpiry(). Vous pouvez consulter la documentation de la méthode ici.

Avec le cas de test suivant, nous observons bien ce concept d’expiration de la donnée :

@Test
public void GivenExpiryEnabledInMemoryCache_WhenAccessWithKey_ThenDataShouldExpire() throws InterruptedException{
 Cache expiryEnabledInMemoryCache = CacheHelper.
 createExpiryEnabledInMemoryCache("expiryEnabledInMemoryCache", Integer.class, String.class, 2);
 expiryEnabledInMemoryCache.put(1, "Meritis");
 TimeUnit.SECONDS.sleep(4);
 assertNull(expiryEnabledInMemoryCache.get(1));
}

Dans ce cas, nous avons créé un cache avec une période d’expiration de données de 2 secondes. Nous avons mis en cache l’entrée (1, « Meritis ») puis, nous avons mis en pause le thread de 4 secondes. Quand on effectue une recherche avec la clé que nous avons insérée, impossible alors de la retrouver. Preuve que cette entrée a expiré.

  • Persistance sur disque

Il se peut qu’on ne veuille pas stocker en mémoire toutes les valeurs du cache. Ainsi, il est possible de les sauvegarder sur le disque. Voici comment configurer le cache :

public static Cache createPersistenceStorageCache(String cacheName, Class<?> ketType, Class<?> valueType) {
 CacheConfigurationBuilder<?, ?> configurationBuilder = CacheConfigurationBuilder
 .newCacheConfigurationBuilder(ketType, valueType, ResourcePoolsBuilder.heap(100).disk(10, MemoryUnit.MB));
 CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
 .with(CacheManagerBuilder.persistence("D:\\Zeniou\\articles\\Ehcache"))
 .withCache(cacheName, configurationBuilder)
 .build();
 cacheManager.init();
 return cacheManager.getCache(cacheName, ketType, valueType);
}

La différence entre cette configuration et celle du cache en mémoire est :

  • Nous avons spécifié le dossier dans lequel sera effectuée la persistance du cache.
  • Nous avons limité l’espace alloué au cache à 10 Mb.

Test du cache

@Test
public void GivenPersistenceCache_WhenAccessWithKey_ThenGetTheValue(){
 Cache persistenceStorageCache = CacheHelper
 .createPersistenceStorageCache("persistenceStorageCache", Integer.class, String.class);
 String value = "Meritis";
 IntStream.range(1,2000).boxed().forEach(i -> persistenceStorageCache.put(i, value));
 assertTrue(value.equals(persistenceStorageCache.get(1999)));
}

C’est un cas de test assez simple. Le test passe au vert et on observe que les fichiers du cache sont créés sur le disque :

III/ Quelles alternatives à Ehcache ?

Il existe en effet d’autres alternatives à Ehcache. Citons par exemple :

  • Apache Ignite
  • Hazelcast
  • Redis
  • Guava

Nous avons donc présenté Ehcache, et vu comment créer, configurer et utiliser un cache en mémoire. Ensuite, vous avez pu découvrir quelques fonctionnalités de l’Ehcache, telles que la persistance sur disque et l’expiration du données dans le cache. Enfin, nous avons cité quelques alternatives de l’Ehcache. Pour autant, nous n’en avons pas terminé avec Ehcache. Rendez-vous dans un prochain article pour aborder l’utilisation de l’Ehcache avec Spring boot.

Notes

JSR : Java Specification Requests

JSR 107 : JCACHE – Java Temporary Caching API

Références

https://en.wikipedia.org/wiki/Ehcache

https://www.jcp.org/en/jsr/detail?id=107

https://github.com/jsr107/jsr107spec

https://www.ehcache.org/

https://medium.com/swlh/build-high-performance-java-applications-with-ehcache-393f980bd8d0

https://stackshare.io/ehcache

Pas encore de commentaires

Publier un commentaire

Auteur

Soufiane ZENIOU

Sofiane est un développeur junior passionné par l'écosystème Java et avide de nouveaux challenges.