Introduzione a Ehcache

1. Panoramica

In questo articolo, introdurremo Ehcache, una cache basata su Java open source ampiamente utilizzata. È dotato di memorie e archivi su disco, listener, caricatori di cache, API RESTful e SOAP e altre funzionalità molto utili.

Per mostrare come il caching può ottimizzare la nostra applicazione, creeremo un metodo semplice che calcolerà i valori quadrati dei numeri forniti. Ad ogni chiamata, il metodo chiamerà il metodo calculateSquareOfNumber (int number) e stamperà il messaggio informativo sulla console.

Con questo semplice esempio, vogliamo mostrare che il calcolo dei valori al quadrato viene eseguito una sola volta e ogni altra chiamata con lo stesso valore di input restituisce il risultato dalla cache.

È importante notare che siamo concentrati interamente su Ehcache stesso (senza Spring); se vuoi vedere come funziona Ehcache con Spring, dai un'occhiata a leggere questo articolo.

2. Dipendenze di Maven

Per utilizzare Ehcache dobbiamo aggiungere questa dipendenza Maven:

 org.ehcache ehcache 3.1.3 

L'ultima versione del manufatto Ehcache può essere trovata qui.

3. Configurazione della cache

Ehcache può essere configurato in due modi:

  • Il primo modo è tramite Java POJO in cui tutti i parametri di configurazione sono configurati tramite l'API Ehcache
  • Il secondo modo è la configurazione tramite file XML dove possiamo configurare Ehcache secondo la definizione dello schema fornito

In questo articolo, mostreremo entrambi gli approcci: Java e configurazione XML.

3.1. Configurazione Java

Questa sottosezione mostrerà quanto sia facile configurare Ehcache con POJO. Inoltre, creeremo una classe helper per una più facile configurazione e disponibilità della 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 }

Per inizializzare la nostra cache, innanzitutto, dobbiamo definire l' oggetto Ehcache CacheManager . In questo esempio, stiamo creando una cache predefinita squaredNumber ” con l' API newCacheManagerBuilder () .

La cache sarà semplicemente mappare intere chiavi Integer valori.

Si noti come, prima di iniziare a utilizzare la cache definita, è necessario inizializzare l' oggetto CacheManager con il metodo init () .

Infine, per ottenere la nostra cache, possiamo semplicemente usare l' API getCache () con il nome, la chiave e i tipi di valore forniti della nostra cache.

Con quelle poche righe, abbiamo creato la nostra prima cache che è ora disponibile per la nostra applicazione.

3.2. Configurazione XML

L'oggetto di configurazione della sottosezione 3.1. è uguale all'utilizzo di questa configurazione XML:

 java.lang.Integer java.lang.Integer 10 

E per includere questa cache nella nostra applicazione Java, dobbiamo leggere il file di configurazione XML in Java:

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

4. Ehcache Test

Nella sezione 3. abbiamo mostrato come definire una cache semplice per i propri scopi. Per dimostrare che la memorizzazione nella cache funziona effettivamente, creeremo la classe SquaredCalculator che calcolerà il valore quadrato dell'input fornito e memorizzerà il valore calcolato in una cache.

Ovviamente, se la cache contiene già un valore calcolato, restituiremo il valore memorizzato nella cache ed eviteremo calcoli non necessari:

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

Per completare il nostro scenario di test, avremo anche bisogno del codice che calcolerà i valori quadrati:

@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"); } }

Se eseguiamo il nostro test, otterremo questo risultato nella nostra 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

Come puoi notare, il metodo calcola () esegue i calcoli solo alla prima chiamata. Alla seconda chiamata, tutti i valori sono stati trovati nella cache e restituiti da essa.

5. Altre opzioni di configurazione di Ehcache

Quando abbiamo creato la nostra cache nell'esempio precedente, era una semplice cache senza opzioni speciali. Questa sezione mostrerà altre opzioni utili nella creazione della cache.

5.1. Persistenza del disco

Se ci sono troppi valori da memorizzare nella cache, possiamo memorizzare alcuni di questi valori sul disco rigido.

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

Invece del CacheManager predefinito , ora utilizziamo PersistentCacheManager che persisterà tutti i valori che non possono essere salvati in memoria.

Dalla configurazione, possiamo vedere che la cache salverà 10 elementi in memoria e allocherà 10 MB sul disco rigido per la persistenza.

5.2. Data scadenza

Se memorizziamo molti dati nella cache, è naturale che salviamo i dati memorizzati nella cache per un certo periodo di tempo in modo da evitare un grande utilizzo della memoria.

Ehcache controlla l'aggiornamento dei dati tramite l' interfaccia Expiry :

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

In questa cache, tutti i dati vivranno per 60 secondi e dopo quel periodo di tempo verranno eliminati dalla memoria.

6. Conclusione

In questo articolo, abbiamo mostrato come utilizzare la semplice cache Ehcache in un'applicazione Java.

Nel nostro esempio, abbiamo visto che anche una cache configurata semplicemente può salvare molte operazioni non necessarie. Inoltre, abbiamo dimostrato che possiamo configurare le cache tramite POJO e XML e che Ehcache ha alcune caratteristiche interessanti, come la persistenza e la scadenza dei dati.

Come sempre, il codice di questo articolo può essere trovato su GitHub.