1. Información general
En este artículo, presentaremos Ehcache, una caché basada en Java de código abierto y ampliamente utilizada. Cuenta con almacenamiento de memoria y disco, escuchas, cargadores de caché, API RESTful y SOAP y otras características muy útiles.
Para mostrar cómo el almacenamiento en caché puede optimizar nuestra aplicación, crearemos un método simple que calculará los valores cuadrados de los números proporcionados. En cada llamada, el método llamará al método calculateSquareOfNumber (int number) e imprimirá un mensaje de información en la consola.
Con este ejemplo simple, queremos mostrar que el cálculo de los valores al cuadrado se realiza solo una vez, y cada otra llamada con el mismo valor de entrada está devolviendo el resultado de la caché.
Es importante notar que estamos completamente enfocados en Ehcache en sí (sin Spring); Si desea ver cómo funciona Ehcache con Spring, lea este artículo.
2. Dependencias de Maven
Para usar Ehcache necesitamos agregar esta dependencia de Maven:
org.ehcache ehcache 3.1.3
La última versión del artefacto Ehcache se puede encontrar aquí.
3. Configuración de caché
Ehcache se puede configurar de dos formas:
- La primera forma es a través de Java POJO donde todos los parámetros de configuración se configuran a través de la API Ehcache
- La segunda forma es la configuración a través de un archivo XML donde podemos configurar Ehcache de acuerdo con la definición de esquema proporcionada
En este artículo, mostraremos ambos enfoques: Java y configuración XML.
3.1. Configuración de Java
Esta subsección mostrará lo fácil que es configurar Ehcache con POJO. Además, crearemos una clase auxiliar para facilitar la configuración y disponibilidad de la caché:
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 }
Para inicializar nuestro caché, primero, necesitamos definir el objeto Ehcache CacheManager . En este ejemplo, estamos creando un "squaredNumber" de caché predeterminado con la API newCacheManagerBuilder () .
El caché simplemente asignar enteros claves para Integer valores.
Observe cómo, antes de que comencemos a usar la caché definida, necesitamos inicializar el objeto CacheManager con el método init () .
Finalmente, para obtener nuestro caché, podemos usar la API getCache () con el nombre, clave y tipos de valor proporcionados de nuestro caché.
Con esas pocas líneas, creamos nuestro primer caché que ahora está disponible para nuestra aplicación.
3.2. Configuración XML
El objeto de configuración de la subsección 3.1. es igual a usar esta configuración XML:
java.lang.Integer java.lang.Integer 10
Y para incluir este caché en nuestra aplicación Java, necesitamos leer el archivo de configuración XML en Java:
URL myUrl = getClass().getResource(xmlFile); XmlConfiguration xmlConfig = new XmlConfiguration(myUrl); CacheManager myCacheManager = CacheManagerBuilder .newCacheManager(xmlConfig);
4. Prueba de Ehcache
En la sección 3. mostramos cómo puede definir una caché simple para sus propósitos. Para mostrar que el almacenamiento en caché realmente funciona, crearemos la clase SquaredCalculator que calculará el valor al cuadrado de la entrada proporcionada y almacenará el valor calculado en una caché.
Por supuesto, si la caché ya contiene un valor calculado, devolveremos el valor almacenado en caché y evitaremos cálculos innecesarios:
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; }
Para completar nuestro escenario de prueba, también necesitaremos el código que calculará los valores cuadrados:
@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 ejecutamos nuestra prueba, obtendremos este resultado en nuestra consola:
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
Como puede notar, el método calculate () estaba haciendo cálculos solo en la primera llamada. En la segunda llamada, todos los valores se encontraron en la caché y se devolvieron de ella.
5. Otras opciones de configuración de Ehcache
Cuando creamos nuestro caché en el ejemplo anterior, era un caché simple sin opciones especiales. Esta sección mostrará otras opciones que son útiles en la creación de caché.
5.1. Persistencia del disco
Si hay demasiados valores para almacenar en la caché, podemos almacenar algunos de esos valores en el disco duro.
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();
En lugar del CacheManager predeterminado , ahora usamos PersistentCacheManager que conservará todos los valores que no se pueden guardar en la memoria.
A partir de la configuración, podemos ver que el caché guardará 10 elementos en la memoria y asignará 10 MB en el disco duro para la persistencia.
5.2. Caducidad de datos
Si almacenamos en caché una gran cantidad de datos, es natural que guardemos los datos almacenados en caché durante un período de tiempo para evitar un gran uso de memoria.
Ehcache de datos controla frescura a través de caducidad interfaz:
CacheConfiguration cacheConfiguration = CacheConfigurationBuilder .newCacheConfigurationBuilder(Integer.class, Integer.class, ResourcePoolsBuilder.heap(100)) .withExpiry(Expirations.timeToLiveExpiration(Duration.of(60, TimeUnit.SECONDS))).build();
En este caché, todos los datos vivirán durante 60 segundos y después de ese período de tiempo, se eliminarán de la memoria.
6. Conclusión
En este artículo, mostramos cómo usar el almacenamiento en caché Ehcache simple en una aplicación Java.
En nuestro ejemplo, vimos que incluso una caché simplemente configurada puede ahorrar muchas operaciones innecesarias. Además, mostramos que podemos configurar cachés a través de POJO y XML y que Ehcache tiene algunas características interesantes, como la persistencia y la caducidad de los datos.
Como siempre, el código de este artículo se puede encontrar en GitHub.