Almacenamiento de datos en caché con Spring Boot

En este artículo les propongo un ejemplo desarrollado en Spring Boot donde podemos verificar la utilidad de una estrategia de almacenamiento en cache

En aws.amazon.com podemos encontrar un concepto excelente sobre este tema : “Una memoria caché es una capa de almacenamiento de datos de alta velocidad que almacena un subconjunto de datos, normalmente transitorios, de modo que las solicitudes futuras de dichos datos se atienden con mayor rapidez que si se debe acceder a los datos desde la ubicación de almacenamiento principal. El almacenamiento en caché permite reutilizar de forma eficaz los datos recuperados o procesados anteriormente.”

Esto que quiere decir de forma simple, que si ya consumimos un dato, podemos almacenarlo de cierta manera donde recuperarlo nuevamente no suponga un gasto innecesario de rendimiento.

En este artículo les propongo un ejemplo desarrollado en Spring Boot donde podemos verificar la utilidad de una estrategia de almacenamiento en cache, las principales dependencias de este proyecto son:

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

El objetivo de este ejercicio es crear un repositorio de frutas donde podemos obtener una fruta por su nombre, si la fruta fue solicitada anteriormente entonces devolvemos el resultado almacenado en caché, lo primero es crear la clase modelo Fruta:

public class Fruit {
 private int price;
 private String name;
//getters and setters
public Fruit(int price, String name) {
    super();
    this.price = price;
    this.name = name;
 }
}

Definido el modelo creamos el Repositorio de frutas:

public interface FruitRepository {
     Fruit getByName(String name);
}

Como el objetivo es demostrar la mejora del tiempo de ejecución añadimos un retraso en la ejecución el método getByName(), para ellos creamos una clase que implemente la interfaz FruitRepository, el método SlowService() nos permite adicionar un retraso de 4 s a la ejecución del método getByName():

@Component
public class MirrorFruitRepository implements FruitRepository {
@Override
@Cacheable("fruits")
public Fruit getByName(String name) {
    SlowService();
    return new Fruit(8,name);
  }
  private void SlowService() {
    try {
      long time = 4000L;
      Thread.sleep(time);
    } catch (InterruptedException e) {
      throw new IllegalStateException(e);
    }
  }
}

El próximo paso es definir una clase que nos permita generar los logs de las peticiones al método getByName():

@Component
public class AppRunner implements CommandLineRunner {
private static final Logger logger = LoggerFactory.getLogger(AppRunner.class);
  private final FruitRepository fruitRepository;
  public AppRunner(FruitRepository fruitRepository) {
    this.fruitRepository = fruitRepository;
  }
@Override
public void run(String... args) throws Exception {
    logger.info("....Searching fruits");
    logger.info("Coco -->" + fruitRepository.getByName("Coco"));
    logger.info("Coco -->" + fruitRepository.getByName("Coco"));
    logger.info("Guayaba -->" + fruitRepository.getByName("Guayaba"));
    logger.info("Coco -->" + fruitRepository.getByName("Coco"));
    logger.info("Pera -->" + fruitRepository.getByName("Pera"));
    logger.info("Mango -->" + fruitRepository.getByName("Mango"));
}
}

De esta forma podemos comprobar que el tiempo normal de respuesta cuando se pide una fruta es de 4 s, sin embargo después de pedida una fruta si se vuelve a solicitar el tiempo de respuesta se reduce drásticamente, esto se debe a que el dato que viaja como respuesta es extraído del almacenamiento en caché.

Un apunte importante es la adición de la anotación @EnableCaching en el path de nuestro proyecto:

@SpringBootApplication
@EnableCaching
public class Main {
public static void main(String[] args) {
    SpringApplication.run(Main.class, args);
    System.out.println("End of Example");
}
}

Espero que este artículo te resultara útil, aquí te dejo el código completo del ejemplo, en este mismo blog tenemos otro artículo que profundiza más el tema y lo aterriza a un entorno distribuido.

Disfruta programando y no dejes nunca de aprender.