En esta entrada del blog, descubriremos cómo almacenar datos en caché fácilmente utilizando Caché de primavera
y Couchbase
como gerente de una tienda de respaldo.
Índice
- Introducción
- En
Caché
Abstracción - Implementación de Couchbase
- En
couchbase-spring-cache
y ponerlo en práctica - Conclusión
Introducción
Hubo mucho trabajo relacionado con Primavera
¡últimamente! Hemos estado ocupados trabajando en el Spring Data Couchbase
conector para actualizarlo a la generación 2.x del SDK de Java, lo que conlleva una serie de nuevas funciones y mejoras (pero hablaremos de ello más adelante)...
En el camino, nos dimos cuenta de que hay algunas clases en el proyecto que no están realmente relacionadas directamente con Datos de primavera
y, como tal, no ha tenido que ceñirse a su ciclo formal de lanzamientos "Release Train": el caché
paquete.
Así que empezamos un nuevo y sencillo proyecto de ejemplo de Spring Boot Cache para alojar el 2.x
generación del Caché Couchbase Spring
aplicación en github (couchbaselabs/couchbase-spring-cache
).
Veamos cómo se puede aprovechar para introducir fácilmente el almacenamiento en caché respaldado por Couchbase en un proyecto Spring.
En Caché
Abstracción
Spring Framework viene con una abstracción ligera de un Caché
que los desarrolladores pueden utilizar automáticamente anotando métodos en sus clases (por ejemplo, en una clase @Repositorio
estereotipo).
Para hacer uso de los mecanismos de caché de arranque de Spring, basta con anotar los métodos con un puñado de anotaciones relacionadas con la caché:
@Cacheable
dejará que se ejecute la primera invocación del método anotado con un conjunto determinado de parámetros de entrada, pero el resultado se almacenará en caché y las invocaciones posteriores (con el mismo conjunto) se servirán de forma transparente desde la caché.@CachePut
siempre invocará el método y almacenará en caché su resultado (a diferencia de@Cacheable
no optimiza el flujo de invocación).@CacheEvict
calculará una clave de caché a partir de los parámetros del método anotado y la eliminará de la caché cuando se ejecute el método (por ejemplo, porque invocar este método hace que una entrada sea obsoleta).@Caching
permite reagrupar comportamientos de la anotación anterior en una sola.@CacheConfig
nos permite tener parámetros de caché comunes establecidos en toda una clase.
Implementación de Couchbase
El framework establece el mecanismo abstracto, pero debe elegirse una implementación de respaldo real. Spring viene con algunas de ellas (en memoria Mapa
, EhCache
, Gemfire
...), pero es absolutamente posible definir otras personalizadas, simplemente implantando un Caché
y un Gestor de caché
y hacerlo visible en el contexto de Spring.
Ese es el objetivo de couchbase-spring-cache
.
Cada caché tiene un nombre, y cada valor en la caché tiene una clave de caché. La implementación de Couchbase traducirá eso en una clave de documento que refleje ese...
- este es un
Caché
documento relacionado (por defecto utilizando el prefijo "caché:
“) - se refiere a un determinado
Caché
(añadiendo elNOMBRE_DE_LA_CACHE
al prefijo anterior) - almacena un valor de caché concreto en
CACHE_KEY
(así que en general "cache:CACHE_NAME:CACHE_KEY
“).
Por ahora los valores deben ser Serializable
y se almacenan como SerializableDocument
del 2.x
Java SDK, pero en el futuro podrían ofrecerse alternativas de transcodificación, por ejemplo JSON
/JsonDocument
…
En couchbase-spring-cache
y ponerlo en práctica
Nota:
En el momento de escribir estas líneas, el proyecto se encuentra en
1.0-SNAPSHOT
por lo que no está disponible enMaven Central
todavía. Tendrás que compilar manualmente el jar y añadirlo a tu repositorio local de Maven.
Descargar y construir el couchbase-spring-cache
proyecto
Comienza clonando el proyecto desde github:
1 2 |
git clonar https://github.com/couchbaselabs/couchbase-spring-cache.git cd couchbase-primavera-caché |
A continuación, compílelo e instálelo localmente utilizando Maven:
1 |
mvn limpiar instale |
Debería ver un mensaje de éxito indicando la versión creada y dónde se instaló:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
[INFO] Instalación de /ruta/a/couchbase-primavera-caché/objetivo/couchbase-primavera-caché-<span estilo="color de fondo: amarillo">1.0-SNAPSHOT.tarro</span> a <span estilo="color de fondo: naranja">/ruta/a/.m2/repositorio/</span><span estilo="color de fondo: gris claro">com/couchbase/cliente/couchbase-primavera-caché/1.0-SNAPSHOT/couchbase-primavera-caché-1.0-SNAPSHOT.tarro</span> [INFO] Instalación de /ruta/a/couchbase-primavera-caché/pom.xml a /ruta/a/.m2/repositorio/com/couchbase/cliente/couchbase-primavera-caché/1.0-SNAPSHOT/couchbase-primavera-caché-1.0-SNAPSHOT.pom [INFO] ------------------------------------------------------------------------ [INFO] CONSTRUIR ÉXITO [INFO] ------------------------------------------------------------------------ |
Iniciar un proyecto tutorial
Construiremos un proyecto de ejemplo de Spring Cache utilizando Maven y Spring Boot
como base.
Comience por crear la siguiente estructura de directorios para el proyecto en un directorio raíz de su elección (utilizaremos cbcache
aquí):
1 2 3 4 5 6 7 |
cbcache └── src └── principal └── java └── com └── couchbase └── demo |
Por ejemplo, utilice el siguiente comando:
1 2 |
mkdir -p cbcache/src/principal/java/com/couchbase/demo/ cd cbcache |
A continuación, inicie el POM en la raíz de cbcache en pom.xml
con el siguiente contenido:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
<!--?xml versión="1.0" codificación="UTF-8"?--> 4.0.0 com.couchbase.demo cbcache 0.1.0 org.springframework.arranque primavera-arranque-arranque-padre 1.3.0.RELEASE 1.8 org.springframework.arranque primavera-arranque-arranque org.springframework primavera-contexto <!--el couchbase caché artefacto nosotros construido antes--> com.couchbase.cliente couchbase-primavera-caché 1.0-SNAPSHOT org.springframework.arranque primavera-arranque-maven-plugin |
Añadir entidad de gestión de libros y repositorio
Utilizaremos el ejemplo de un Reserve
(tal y como se encuentra en el repositorio "COMENZAR - Almacenamiento de datos en caché con Spring"guía oficial de Spring.io).
Crear el Reserve
clase de entidad en src/main/java/com/couchbase/demo/Libro.java
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
importar java.io.Serializable; público clase Reserve implementa Serializable { privado estático final largo serialVersionUID = -7674163614777124381L; privado Cadena isbn; privado Cadena título; público Reserve(Cadena isbn, Cadena título) { este.isbn = isbn; este.título = título; } público Cadena getIsbn() { devolver isbn; } público void setIsbn(Cadena isbn) { este.isbn = isbn; } público Cadena getTitle() { devolver título; } público void setTitle(Cadena título) { este.título = título; } @Anular público Cadena toString() { devolver "Libro{" + "isbn=" + isbn + ''' + ", title='" + título + ''' + '}'; } } |
Tenga en cuenta la
Reserve
clase esSerializable
Esto es importante por ahora para el almacenamiento de Couchbase.
Crear una interfaz de repositorio simple y una implementación ingenua que simule un retraso:
en src/main/java/com/couchbase/demo/BookRepository.java
:
1 2 3 4 5 6 7 |
paquete com.couchbase.demo; público interfaz BookRepository { Reserve getByIsbn(Cadena isbn); } |
en src/main/java/com/couchbase/demo/SimpleBookRepository.java
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
paquete com.couchbase.demo; importar org.slf4j.Registrador; importar org.slf4j.LoggerFactory; importar org.springframework.estereotipo.Componente; @Componente público clase SimpleBookRepository implementa BookRepository { privado estático final Registrador registro = LoggerFactory.getLogger(SimpleBookRepository.clase); @Anular público Reserve getByIsbn(Cadena isbn) { simulateSlowService(); Reserve resultado = nuevo Reserve(isbn, "Algún libro"); registro.información("Actual fetch of" + isbn); devolver resultado; } // No hagas esto en casa privado void simulateSlowService() { pruebe { largo tiempo = 5000L; Hilo.dormir(tiempo); } captura (InterruptedException e) { tirar nuevo IllegalStateException(e); } } } |
Principal Spring Boot
Aplicación
Por último, cree una Aplicación que utilice el repositorio en src/main/java/com/couchbase/demo/Application.java
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
paquete com.couchbase.demo; importar org.slf4j.Registrador; importar org.slf4j.LoggerFactory; importar org.springframework.judías.fábrica.anotación.Autowired; importar org.springframework.arranque.CommandLineRunner; importar org.springframework.arranque.SpringApplication; importar org.springframework.arranque.autoconfigure.SpringBootApplication; importar org.springframework.estereotipo.Componente; @SpringBootApplication público clase Aplicación { privado estático final Registrador registro = LoggerFactory.getLogger(Aplicación.clase); @Componente estático clase Corredor implementa CommandLineRunner { @Autowired privado BookRepository repositorio de libros; @Anular público void ejecute(Cadena... args) lanza Excepción { largo iniciar; registro.información(".... Búsqueda de libros"); fetchAndLog("isbn-1234"); fetchAndLog("isbn-1234"); fetchAndLog("isbn-1234"); fetchAndLog("isbn-8888"); fetchAndLog("isbn-8888"); } privado void fetchAndLog(Cadena isbn) { largo iniciar = Sistema.currentTimeMillis(); Reserve Libro = repositorio de libros.getByIsbn(isbn); largo tiempo = Sistema.currentTimeMillis() - iniciar; registro.información(isbn + " --> " + Libro + " en " + tiempo + "ms"); } } público estático void principal(Cadena[] args) { SpringApplication.ejecute(Aplicación.clase, args); } } |
Si ejecuta la función Aplicación
's principal
en su IDE (o si invoca "mvn spring-boot:ejecutar
" desde la línea de comandos), observará que todas las llamadas son, en efecto, bastante lentas:
1 2 3 4 5 6 7 8 9 10 11 |
[...] .... Buscar en libros [...] Actual buscar de isbn-1234 [...] isbn-1234 --> Reserve{isbn=isbn-1234, título='Menudo libro'} en 5001ms [...] Actual buscar de isbn-1234 [...] isbn-1234 --> Reserve{isbn=isbn-1234, título='Menudo libro'} en 5004ms [...] Actual buscar de isbn-1234 [...] isbn-1234 --> Reserve{isbn=isbn-1234, título='Menudo libro'} en 5004ms [...] Actual buscar de isbn-8888 [...] isbn-8888 --> Reserve{isbn=isbn-8888, título='Menudo libro'} en 5003ms [...] Actual buscar de isbn-8888 [...] isbn-8888 --> Reserve{isbn=isbn-8888, título='Menudo libro'} en 5003ms |
Añadir capacidades de almacenamiento en caché de Spring Boot
Para activar el almacenamiento en caché, debe seguir algunos pasos: en primer lugar, debe ofrecer a Spring un archivo Gestor de caché
@Bean
…
Dado que vamos a utilizar el CouchbaseCacheManager
(por supuesto), necesitaremos conectarnos a un Grupo
y utilizar un Cubo
(la unidad de almacenamiento donde couchbase almacenará los documentos de la caché).
Así que el CouchbaseCacheManager
necesita una correspondencia entre Caché
y los correspondientes Cubo
a utilizar, pasado como Mapa
.
En src/main/java/com/couchbase/demo/Application.java
añade las siguientes declaraciones de bean:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
público estático final Cadena BOOK_CACHE = "libros"; @Judía(destroyMethod = "desconectar") público Grupo grupo() { //esto conecta con una instancia de Couchbase que se ejecuta en localhost devolver CouchbaseCluster.crear(); } @Judía(destroyMethod = "cerrar") público Cubo cubo() { //este será el cubo donde se almacenarán todos los datos relacionados con la caché //note that the bucket "default" must exist devolver grupo().openBucket("por defecto", ""); } @Judía público Gestor de caché cacheManager() { Mapa<Cadena, Cubo> cartografía = nuevo HashMap<Cadena, Cubo>(); //haremos que este gestor de caché reconozca una única caché llamada "libros" cartografía.poner(BOOK_CACHE, cubo()); devolver nuevo CouchbaseCacheManager(cartografía); } |
A continuación, desea activar el escaneo de anotaciones relacionadas con la caché y el proxy asociado colocando la etiqueta @HabilitarCaché
en el Aplicación
clase.
Activar caché en SimpleBookRepository
Veamos cómo activar el almacenamiento en caché real en nuestro SimpleBookRepository
y compruebe cómo se comporta la aplicación después de eso.
Para hacer getByIsbn
automáticamente en caché en la primera invocación y servir las invocaciones posteriores con datos de la caché, simplemente anótelo así:
1 2 3 4 5 6 7 8 |
@Anular @Almacenable en caché(Aplicación.BOOK_CACHE) //utilizando el nombre de la caché que declaramos anteriormente público Reserve getByIsbn(Cadena isbn) { simulateSlowService(); Reserve resultado = nuevo Reserve(isbn, "Algún libro"); registro.información("Actual fetch of" + isbn); devolver resultado; } |
Vamos a ejecutar la aplicación de nuevo y ver cómo se comporta ahora:
1 2 3 4 5 6 7 8 |
[...] .... Buscar en libros [...] Actual buscar de isbn-1234 [...] isbn-1234 --> Reserve{isbn=isbn-1234, título='Menudo libro'} en 5022ms [...] isbn-1234 --> Reserve{isbn=isbn-1234, título='Menudo libro'} en 3ms [...] isbn-1234 --> Reserve{isbn=isbn-1234, título='Menudo libro'} en 1ms [...] Actual buscar de isbn-8888 [...] isbn-8888 --> Reserve{isbn=isbn-8888, título='Menudo libro'} en 5007ms [...] isbn-8888 --> Reserve{isbn=isbn-8888, título='Menudo libro'} en 1ms |
¡Vaya! Esto es mucho mejor para las invocaciones más allá de la primera, parece que efectivamente se almacena en caché :-)
Ver los datos en Couchbase
Echemos un vistazo rápido a la consola web para verificar que estos magníficos tiempos pueden atribuirse a Couchbase:
- abra una nueva pestaña en su navegador y navegue hasta
http://localhost:8091
. - conectarse a la consola web.
- ir a la
Cubos de datos
y haga clic enDocumentos
para el cubo que haya elegido utilizar ("por defecto").
Lo que ve en esta pantalla (enlace rápido para los perezosos) debería ser similar a esto:
Podemos ver que ambos libros se almacenaron en caché en couchbase, utilizando el método cache:CACHE_NAME:CACHE_KEY
para los ID de los documentos.
Conclusión
Couchbase le facilita el almacenamiento en caché.
Hay mucho más que Caché de primavera
puede hacer por usted (por ejemplo, elegir cómo crear la clave de caché, caché condicional, desalojo de caché, etc...), y hay especificidades de couchbase-spring-cache
(por ejemplo, para la limpieza de la caché puede elegir entre utilizar una vista que sólo eliminará el documento relevante o, si su cubo está dedicado a una única caché, utilizar la función descarga
mecanismo...).
Espero que este tutorial introductorio te haya abierto el apetito sobre la facilidad de uso de la memoria caché con Caché de primavera
y Couchbase
!
Los próximos pasos serán probablemente introducir formatos de almacenamiento alternativos (como JSON) y ofrecer el artefacto en Maven Central o en un repositorio Maven similar de acceso público (Bintray ¿alguien?)...
Esté atento a las próximas noticias relacionadas con la primavera.
Mientras tanto, feliz codificación :)