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 :
[pastacode lang= »java » manual= »%3Cdependency%3E%0A%20%3CgroupId%3Eorg.ehcache%3C%2FgroupId%3E%0A%20%3CartifactId%3Eehcache%3C%2FartifactId%3E%0A%20%3Cversion%3E3.8.1%3C%2Fversion%3E%0A%3C%2Fdependency%3E%0A » message= » » highlight= » » provider= »manual »/]
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 :
- La configuration xml, avec la définition du fichier que l’on retrouve ici.
- 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 :
[pastacode lang= »java » manual= »public%20static%20Cache%20createInMemoryCache(String%20cacheName%2C%20Class%3C%3F%3E%20ketType%2C%20Class%3C%3F%3E%20valueType)%7B%0A%20CacheConfigurationBuilder%3C%3F%2C%20%3F%3E%20configurationBuilder%20%3D%20CacheConfigurationBuilder%0A%20.newCacheConfigurationBuilder(ketType%2C%20valueType%2C%20ResourcePoolsBuilder.heap(100))%3B%0A%20CacheManager%20cacheManager%20%3D%20CacheManagerBuilder.newCacheManagerBuilder()%0A%20.withCache(cacheName%2C%20configurationBuilder)%0A%20.build(true)%3B%0A%20%0A%20return%20cacheManager.getCache(cacheName%2C%20ketType%2C%20valueType)%3B%0A%7D%0A » message= » » highlight= » » provider= »manual »/]
- 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à :
[pastacode lang= »java » manual= »public%20static%20Cache%20createInMemoryCache(String%20cacheName%2C%20Class%3C%3F%3E%20ketType%2C%20Class%3C%3F%3E%20valueType)%7B%0A%20CacheConfigurationBuilder%3C%3F%2C%20%3F%3E%20configurationBuilder%20%3D%20CacheConfigurationBuilder%0A%20.newCacheConfigurationBuilder(ketType%2C%20valueType%2C%20ResourcePoolsBuilder.heap(100))%3B%0A%20CacheManager%20cacheManager%20%3D%20CacheManagerBuilder.newCacheManagerBuilder()%0A%20.withCache(cacheName%2C%20configurationBuilder)%0A%20.build()%3B%0A%20cacheManager.init()%3B%0A%20return%20cacheManager.getCache(cacheName%2C%20ketType%2C%20valueType)%3B%0A%7D%0A » message= » » highlight= » » provider= »manual »/]
Test du cache
[pastacode lang= »java » manual= »%40Test%0Apublic%20void%20GivenCache_WhenAccessWithKey_ThenGetTheValue()%7B%0A%20Cache%20inMemoryCache%20%3D%20CacheHelper.createInMemoryCache(%22inMemoryCache%22%2C%20Integer.class%2C%20String.class)%3B%0A%20Integer%20key%20%3D%201%3B%0A%20String%20value%20%3D%20%22Meritis%22%3B%0A%20assertFalse(inMemoryCache.containsKey(key))%3B%0A%20inMemoryCache.put(key%2C%20value)%3B%0A%20assertTrue(value.equals(inMemoryCache.get(key)))%3B%0A%0A%7D%0A » message= » » highlight= » » provider= »manual »/]
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 :
[pastacode lang= »java » manual= »public%20static%20Cache%20createExpiryEnabledInMemoryCache(String%20cacheName%2C%20Class%3C%3F%3E%20ketType%2C%20Class%3C%3F%3E%20valueType%2C%20int%20expiryPeriod)%7B%0A%20CacheConfigurationBuilder%3C%3F%2C%20%3F%3E%20cacheConfigurationBuilder%20%3D%20CacheConfigurationBuilder%0A%20.newCacheConfigurationBuilder(ketType%2C%20valueType%2C%20ResourcePoolsBuilder.heap(100))%0A%20.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(expiryPeriod)))%3B%0A%20CacheManager%20cacheManager%20%3D%20CacheManagerBuilder.newCacheManagerBuilder()%0A%20.withCache(cacheName%2C%20cacheConfigurationBuilder)%0A%20.build(true)%3B%0A%0A%20return%20cacheManager.getCache(cacheName%2C%20ketType%2C%20valueType)%3B%0A%7D%0A » message= » » highlight= » » provider= »manual »/]
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 :
[pastacode lang= »java » manual= »%40Test%0Apublic%20void%20GivenExpiryEnabledInMemoryCache_WhenAccessWithKey_ThenDataShouldExpire()%20throws%20InterruptedException%7B%0A%20Cache%20expiryEnabledInMemoryCache%20%3D%20CacheHelper.%0A%20createExpiryEnabledInMemoryCache(%22expiryEnabledInMemoryCache%22%2C%20Integer.class%2C%20String.class%2C%202)%3B%0A%20expiryEnabledInMemoryCache.put(1%2C%20%22Meritis%22)%3B%0A%20TimeUnit.SECONDS.sleep(4)%3B%0A%20assertNull(expiryEnabledInMemoryCache.get(1))%3B%0A%7D%0A » message= » » highlight= » » provider= »manual »/]
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 :
[pastacode lang= »java » manual= »public%20static%20Cache%20createPersistenceStorageCache(String%20cacheName%2C%20Class%3C%3F%3E%20ketType%2C%20Class%3C%3F%3E%20valueType)%20%7B%0A%20CacheConfigurationBuilder%3C%3F%2C%20%3F%3E%20configurationBuilder%20%3D%20CacheConfigurationBuilder%0A%20.newCacheConfigurationBuilder(ketType%2C%20valueType%2C%20ResourcePoolsBuilder.heap(100).disk(10%2C%20MemoryUnit.MB))%3B%0A%20CacheManager%20cacheManager%20%3D%20CacheManagerBuilder.newCacheManagerBuilder()%0A%20.with(CacheManagerBuilder.persistence(%22D%3A%5C%5CZeniou%5C%5Carticles%5C%5CEhcache%22))%0A%20.withCache(cacheName%2C%20configurationBuilder)%0A%20.build()%3B%0A%20cacheManager.init()%3B%0A%20return%20cacheManager.getCache(cacheName%2C%20ketType%2C%20valueType)%3B%0A%7D%0A » message= » » highlight= » » provider= »manual »/]
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
[pastacode lang= »java » manual= »%40Test%0Apublic%20void%20GivenPersistenceCache_WhenAccessWithKey_ThenGetTheValue()%7B%0A%20Cache%20persistenceStorageCache%20%3D%20CacheHelper%0A%20.createPersistenceStorageCache(%22persistenceStorageCache%22%2C%20Integer.class%2C%20String.class)%3B%0A%20String%20value%20%3D%20%22Meritis%22%3B%0A%20IntStream.range(1%2C2000).boxed().forEach(i%20-%3E%20persistenceStorageCache.put(i%2C%20value))%3B%0A%20assertTrue(value.equals(persistenceStorageCache.get(1999)))%3B%0A%7D%0A » message= » » highlight= » » provider= »manual »/]
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://medium.com/swlh/build-high-performance-java-applications-with-ehcache-393f980bd8d0
Pas encore de commentaires