Implementando una Cache con Spring


Implementar una Cache con Spring es una tarea bastante fácil, debido a la facilidad de implementación. Para ello Spring nos aporta una serie de anotaciones que podremos ver en el resto del tutorial.

¿Qué es la cache?

La cache es una forma o mecanismo de poder mejorar el rendimiento de un microservicio/servicio o aplicación. De manera que puede almacenar, por lo general, de manera temporal información necesaria, para poder recuperarla de forma rápida.

Esta información suele estar en memoria, y la podemos usar para reducir el número de veces que podemos acceder a una base de datos.

¿Por qué deberíamos de usar una cache?

Muchas veces, se hacen las mismas operaciones contra base de datos, por ejemplo, todos los festivos para un país. Como sabemos que esa información no cambiará, la tendremos en una Cache. Esta información se guardará en memoria (casi siempre) y su recuperación será mucho más rápida.

Tipos de Cache

En memoria: Este es el mejor mecanismo para mejorar el rendimiento de cualquier aplicación, ya que sabemos que la RAM es más rápido que cualquier otro sistema, también más escaso y caro que el disco, por lo que habŕá que tener también en cuenta mecanismos de invalidación como LRU (least recently used), menos usado recientemente. Algunas caches en memoria pueden ser Redis y Memcached.

Cache de Base de datos: Por lo general las Bases de Datos también implementan algún nivel de cache, conocidos aquí pueden ser el primer nivel de Hibernate.

Servidores Web y CDN: Ambos orientados a mostrar contenido web a una mayor velocidad, cacheando contenidos estáticos como puede ser Varnish y así evitando hacer peticiones; o caches localizadas directamente en los navegadores.

Cache con Spring Boot

La integración de una Cache en un proyecto con Spring es realmente sencillo, a partir del uso de anotaciones y el uso de su starter.

Spring nos aporta una capa de abstración para poder hacer uso de diferentes proveedores, sobreescribiendo el CacheManager, pero en este ejemplo únicamente vamos a hacer uso de la cache por defecto de Spring.

Incluir dependencia:

Para empezar incluiríamos la dependencia maven dentro de nuestro proyecto:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
    <version>2.2.4.RELEASE</version>
</dependency>

Activando la cache

@EnableCaching, esta anotación colocada justo con la anotación de @SpringBootApplication, en la clase principal del proyecto, otorgará a nuestra aplicación de las capacidades de la cache de Spring, que es simplemente un concurrent hashmap, pero que como hemos dicho anteriormente, podremos sustituir añadiendo otras caches externas.

Haciendo uso de la cache

@Cacheable: Para permitir a nuestra aplicación hacer uso de la cache tendremos que añadir la anotación @Cacheable, de esta manera Spring sabrá que respuesta de qué métodos pueden estar en la cache.

@CachePut: Esta anotación nos va a permitir poder realizar la actualización de una cache, funciona de manera similar a cacheable.

@CacheEvict: Permite eliminar la información guardada en la cache anteriormente, se pueden eliminar todas las caches o especificar mediante su clave la cache que queremos eliminar.

@Caching: Esta anotación es necesaria cuando queremos hacer uso tanto de Evict como de Put.

NOTA: Nunca hay que utilizar al mismo tiempo put y evict sobre el mismo método ya que podríamos tener efectos no deseados.

Manos a la obra.

A continuación vamos a crear un sistema que nos cachea todas las vacaciones de España.

@SpringBootApplication
public class StratioSpringBootService {

  public static void main(String[] args) {
    SpringApplication.run(StratioSpringBootService.class, args);
  }
}

Creamos o activamos la configuración, para ello, deberos de añadir la anotación @EnableCaching en una clase de configuración, en la que también podremos añadir el bean del cacheManager

@Configuration
@EnableCaching
public class CachingConfig {
 
    @Bean
    public CacheManager cacheManager() {
        return new ConcurrentMapCacheManager("holidays");
    }
}

Generamos el objeto de dominio Holiday,

  @Getter
  @Setter
  public class Holiday {

    private Long id;

    private LocalDate day;
  }

Creamos la capa servicio que atacará al repositorio y será la que sea la responsable de cachear las holidays.

  @Getter
  @Setter
  @AllArgsConstructor
  public class HolidayServiceImpl implements HolidayService{

    private final HolidayRepository holidayRepository;
    

   @Cacheable("holidays")
   public List<Holiday> findAll() {
   return  holidayRepository.findAll();
   }
  }

Con el fragmento de código de arriba lo que hemos hecho ha sido cachear todas las vacaciones que seŕan devueltas por el repositorio. La primera vez que se llame se irá a base de datos y el resto de veces se obtendrán de la cache definida, en este caso, la de por defecto de Spring, que recordemos que es un concurrent hashmap. Este es un ejercicio muy básico, que solo muestra los principios de uso de una cache se Spring, habría que tener en cuenta políticas de actualización, de evict, conexión con terceros, por ejemplo redis, ignite, etc…

En futuros post añadiremos más lógica y complejidad a este ejemplo.

Este ejemplo se puede recuperar de github pulsando aquí. Si necesitas ampliar información puedes echar un ojo a la documentación oficial aquí.


Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *