Introduction à Ehcache

Introduction à Ehcache

1. Vue d'ensemble

Dans cet article, nous présenteronsEhcache, un cache Java open source largement utilisé. Il propose des mémoires, des magasins de disques, des écouteurs, des chargeurs de cache, des API RESTful et SOAP et d’autres fonctionnalités très utiles.

Pour montrer comment la mise en cache peut optimiser notre application, nous allons créer une méthode simple permettant de calculer les valeurs carrées des nombres fournis. À chaque appel, la méthode appellera la méthodecalculateSquareOfNumber(int number) et affichera un message d'information sur la console.

Avec cet exemple simple, nous voulons montrer que le calcul des valeurs au carré est effectué une seule fois et que tous les autres appels avec la même valeur d'entrée renvoient le résultat du cache.

Il est important de noter que nous nous concentrons entièrement sur Ehcache lui-même (sans Spring); si vous voulez voir comment Ehcache fonctionne avec Spring, jetez un œil à readthis article.

2. Dépendances Maven

Pour utiliser Ehcache, nous devons ajouter cette dépendance Maven:


    org.ehcache
    ehcache
    3.1.3

La dernière version de l'artefact Ehcache peut être trouvéehere.

3. Configuration du cache

Ehcache peut être configuré de deux manières:

  • La première consiste à utiliser Java POJO où tous les paramètres de configuration sont configurés via l'API Ehcache

  • La deuxième façon est la configuration via un fichier XML où nous pouvons configurer Ehcache en fonction deprovided schema definition

Dans cet article, nous allons montrer les deux approches - Java et configuration XML.

3.1. Configuration Java

Cette sous-section montrera à quel point il est facile de configurer Ehcache avec des POJO. Nous allons également créer une classe d'assistance pour faciliter la configuration et la disponibilité du cache:

public class CacheHelper {

    private CacheManager cacheManager;
    private Cache squareNumberCache;

    public CacheHelper() {
        cacheManager = CacheManagerBuilder
          .newCacheManagerBuilder().build();
        cacheManager.init();

        squareNumberCache = cacheManager
          .createCache("squaredNumber", CacheConfigurationBuilder
            .newCacheConfigurationBuilder(
              Integer.class, Integer.class,
              ResourcePoolsBuilder.heap(10)));
    }

    public Cache getSquareNumberCacheFromCacheManager() {
        return cacheManager.getCache("squaredNumber", Integer.class, Integer.class);
    }

    // standard getters and setters
}

Pour initialiser notre cache, nous devons d'abord définir l'objet EhcacheCacheManager. Dans cet exemple, nous créons un cache par défautsquaredNumber” avec l'APInewCacheManagerBuilder().

Le cache mappera simplement les clésInteger aux valeursInteger.

Remarquez comment, avant de commencer à utiliser le cache défini, nous devons initialiser l'objetCacheManager avec la méthodeinit().

Enfin, pour obtenir notre cache, nous pouvons simplement utiliser l'APIgetCache() avec les types de nom, de clé et de valeur fournis pour notre cache.

Avec ces quelques lignes, nous avons créé notre premier cache qui est maintenant disponible pour notre application.

3.2. Configuration XML

L'objet de configuration de la sous-section 3.1. équivaut à utiliser cette configuration XML:


    java.lang.Integer
    java.lang.Integer
    10

Et pour inclure ce cache dans notre application Java, nous devons lire le fichier de configuration XML en Java:

URL myUrl = getClass().getResource(xmlFile);
XmlConfiguration xmlConfig = new XmlConfiguration(myUrl);
CacheManager myCacheManager = CacheManagerBuilder
  .newCacheManager(xmlConfig);

4. Test Ehcache

Dans la section 3. nous avons montré comment définir un cache simple pour vos besoins. Pour montrer que la mise en cache fonctionne réellement, nous allons créer la classeSquaredCalculator qui calculera la valeur au carré de l'entrée fournie et stockera la valeur calculée dans un cache.

Bien sûr, si le cache contient déjà une valeur calculée, nous allons retourner la valeur en cache et éviter les calculs inutiles:

public class SquaredCalculator {
    private CacheHelper cache;

    public int getSquareValueOfNumber(int input) {
        if (cache.getSquareNumberCache().containsKey(input)) {
            return cache.getSquareNumberCache().get(input);
        }

        System.out.println("Calculating square value of " + input +
          " and caching result.");

        int squaredValue = (int) Math.pow(input, 2);
        cache.getSquareNumberCache().put(input, squaredValue);

        return squaredValue;
    }

    //standard getters and setters;
}

Pour compléter notre scénario de test, nous aurons également besoin du code qui calculera les valeurs carrées:

@Test
public void whenCalculatingSquareValueAgain_thenCacheHasAllValues() {
    for (int i = 10; i < 15; i++) {
        assertFalse(cacheHelper.getSquareNumberCache().containsKey(i));
        System.out.println("Square value of " + i + " is: "
          + squaredCalculator.getSquareValueOfNumber(i) + "\n");
    }

    for (int i = 10; i < 15; i++) {
        assertTrue(cacheHelper.getSquareNumberCache().containsKey(i));
        System.out.println("Square value of " + i + " is: "
          + squaredCalculator.getSquareValueOfNumber(i) + "\n");
    }
}

Si nous exécutons notre test, nous obtiendrons ce résultat dans notre console:

Calculating square value of 10 and caching result.
Square value of 10 is: 100

Calculating square value of 11 and caching result.
Square value of 11 is: 121

Calculating square value of 12 and caching result.
Square value of 12 is: 144

Calculating square value of 13 and caching result.
Square value of 13 is: 169

Calculating square value of 14 and caching result.
Square value of 14 is: 196

Square value of 10 is: 100
Square value of 11 is: 121
Square value of 12 is: 144
Square value of 13 is: 169
Square value of 14 is: 196

Comme vous pouvez le constater, la méthodecalculate() effectuait des calculs uniquement lors du premier appel. Au deuxième appel, toutes les valeurs ont été trouvées dans le cache et renvoyées à partir de celui-ci.

5. Autres options de configuration d'Ehcache

Lorsque nous avons créé notre cache dans l'exemple précédent, il s'agissait d'un cache simple sans aucune option spéciale. Cette section présentera d'autres options utiles pour la création de cache.

5.1. Persistance du disque

S'il y a trop de valeurs à stocker dans le cache, nous pouvons stocker certaines de ces valeurs sur le disque dur.

PersistentCacheManager persistentCacheManager =
  CacheManagerBuilder.newCacheManagerBuilder()
    .with(CacheManagerBuilder.persistence(getStoragePath()
      + File.separator
      + "squaredValue"))
    .withCache("persistent-cache", CacheConfigurationBuilder
      .newCacheConfigurationBuilder(Integer.class, Integer.class,
        ResourcePoolsBuilder.newResourcePoolsBuilder()
          .heap(10, EntryUnit.ENTRIES)
          .disk(10, MemoryUnit.MB, true))
      )
  .build(true);

persistentCacheManager.close();

Au lieu deCacheManager par défaut, nous utilisons maintenantPersistentCacheManager qui conservera toutes les valeurs qui ne peuvent pas être enregistrées en mémoire.

À partir de la configuration, nous pouvons voir que le cache économisera 10 éléments en mémoire et allouera 10 Mo sur le disque dur pour la persistance.

5.2. Expiration des données

Si nous mettons en cache beaucoup de données, il est naturel que nous conservions les données mises en cache pendant un certain temps afin d’éviter une utilisation excessive de la mémoire.

Ehcache contrôle la fraîcheur des données via l'interfaceExpiry:

CacheConfiguration cacheConfiguration
  = CacheConfigurationBuilder
    .newCacheConfigurationBuilder(Integer.class, Integer.class,
      ResourcePoolsBuilder.heap(100))
    .withExpiry(Expirations.timeToLiveExpiration(Duration.of(60,
      TimeUnit.SECONDS))).build();

Dans ce cache, toutes les données dureront 60 secondes et seront effacées de cette mémoire après cette période.

6. Conclusion

Dans cet article, nous avons montré comment utiliser la mise en cache Ehcache simple dans une application Java.

Dans notre exemple, nous avons vu que même un cache simplement configuré peut économiser beaucoup d'opérations inutiles. Nous avons également montré que nous pouvions configurer des caches à l'aide de POJO et de XML et qu'Ehcache offrait de nombreuses fonctionnalités intéressantes, telles que la persistance et l'expiration des données.

Comme toujours, le code de cet article peut être trouvéon GitHub.