Nesta postagem do blog, descobriremos como armazenar dados em cache facilmente usando Spring Cache
e Couchbase
como gerente de loja de apoio.
Índice
- Uma palavra de apresentação
- O
Cache
Abstração - A implementação do Couchbase
- Obtendo
couchbase-spring-cache
e colocando-o em prática - Conclusão
Uma palavra de apresentação
Houve muito trabalho relacionado a Primavera
ultimamente! Temos estado ocupados trabalhando no Dados do Spring Couchbase
para atualizá-lo para a geração 2.x do Java SDK, trazendo consigo uma série de novos recursos e aprimoramentos (mas falaremos mais sobre isso em uma postagem posterior no blog)...
Ao longo do caminho, percebemos que há algumas classes no projeto que não estão realmente relacionadas diretamente a Dados do Spring
e, como tal, não precisou aderir ao seu ciclo formal de lançamento "Release Train": o cache
pacote.
Portanto, iniciamos um novo projeto de exemplo simples do Spring Boot Cache para hospedar o 2.x
geração do Couchbase Spring Cache
implementação no github (couchbaselabs/couchbase-spring-cache
).
Vamos dar uma olhada em como ele pode ser aproveitado para introduzir facilmente o cache com base no Couchbase em um projeto Spring!
O Cache
Abstração
O Spring Framework vem com uma abstração leve de um Cache
que os desenvolvedores podem usar automaticamente ao anotar métodos em suas classes (por exemplo, em um @Repositório
estereótipo).
Para usar os mecanismos de cache de inicialização do Spring, basta anotar seus métodos com um punhado de anotações relacionadas ao cache:
@Cacheable
permitirá que a primeira invocação do método anotado com um determinado conjunto de parâmetros de entrada seja executada, mas o resultado será armazenado em cache e as invocações subsequentes (com o mesmo conjunto) serão atendidas de forma transparente a partir do cache.@CachePut
sempre invocará o método e armazenará em cache seu resultado (ao contrário de@Cacheable
não otimiza o fluxo de invocação).@CacheEvict
calculará uma chave de cache a partir dos parâmetros do método anotado e a removerá do cache quando o método for executado (por exemplo, porque a invocação desse método torna uma entrada obsoleta).@Caching
permite reagrupar o comportamento da anotação anterior em uma única anotação.@CacheConfig
permite que tenhamos parâmetros de cache comuns definidos em uma classe inteira.
A implementação do Couchbase
O mecanismo abstrato é implementado pela estrutura, mas é necessário escolher uma implementação de apoio real. O Spring vem com alguns deles (na memória Mapa
, EhCache
, Gemfire
...), mas é absolutamente possível definir personalizados, simplesmente implementando um Cache
e um Gerenciador de cache
e torná-lo visível no contexto do Spring.
Esse é o foco de couchbase-spring-cache
.
Cada cache tem um nome, e cada valor no cache tem uma chave de cache. A implementação do Couchbase traduzirá isso em uma chave de documento que reflete esse...
- este é um
Cache
documento relacionado (por padrão, usando o prefixo "cache:
“) - está relacionado a um determinado
Cache
(adicionando oNOME DO CACHE
para o prefixo acima) - ele armazena um determinado valor de cache em
CACHE_KEY
(portanto, no final das contas "cache:CACHE_NAME:CACHE_KEY
“).
Por enquanto, os valores devem ser Serializável
e são armazenados como um Documento serializável
do 2.x
Java SDK, mas a transcodificação alternativa poderá ser oferecida no futuro, por exemplo. JSON
/JsonDocument
…
Obtendo couchbase-spring-cache
e colocando-o em prática
Observação:
No momento em que este texto foi escrito, o projeto estava em
1.0-SNAPSHOT
portanto, não está disponível na versãoCentral Maven
ainda. Você terá que compilar manualmente o jar e adicioná-lo ao seu repositório Maven local.
Download e criação do couchbase-spring-cache
projeto
Comece clonando o projeto do github:
1 2 |
git clone https://github.com/couchbaselabs/couchbase-spring-cache.git cd couchbase-mola-cache |
Em seguida, crie e instale-o localmente usando o Maven:
1 |
mvn limpo instalar |
Você deverá ver uma mensagem de sucesso indicando a versão criada e onde ela foi instalada:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
[INFORMAÇÕES] Instalação /caminho/para/couchbase-mola-cache/alvo/couchbase-mola-cache-<extensão estilo="cor de fundo: amarelo">1.0-FOTOGRAFIA.frasco</extensão> para <extensão estilo="cor de fundo: laranja">/caminho/para/.m2/repositório/</extensão><extensão estilo="cor de fundo: cinza claro">com/couchbase/cliente/couchbase-mola-cache/1.0-FOTOGRAFIA/couchbase-mola-cache-1.0-FOTOGRAFIA.frasco</extensão> [INFORMAÇÕES] Instalação /caminho/para/couchbase-mola-cache/pom.xml para /caminho/para/.m2/repositório/com/couchbase/cliente/couchbase-mola-cache/1.0-FOTOGRAFIA/couchbase-mola-cache-1.0-FOTOGRAFIA.pom [INFORMAÇÕES] ------------------------------------------------------------------------ [INFORMAÇÕES] CONSTRUIR SUCESSO [INFORMAÇÕES] ------------------------------------------------------------------------ |
Iniciando um projeto de tutorial
Criaremos um projeto de exemplo do Spring Cache usando o Maven e o Inicialização do Spring
como base.
Comece criando a seguinte estrutura de diretórios para o projeto em um diretório raiz de sua escolha (usaremos cbcache
aqui):
1 2 3 4 5 6 7 |
cbcache └── src └── principal └── java └── com └── couchbase └── demonstração |
Por exemplo, use o seguinte comando:
1 2 |
mkdir -p cbcache/src/principal/java/com/couchbase/demonstração/ cd cbcache |
Em seguida, inicie o POM na raiz do cbcache em pom.xml
com o seguinte conteúdo:
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 versão="1.0" codificação="UTF-8"?--> 4.0.0 com.couchbase.demonstração cbcache 0.1.0 org.estrutura de mola.inicialização mola-inicialização-inicial-pai 1.3.0.RELEASE 1.8 org.estrutura de mola.inicialização mola-inicialização-inicial org.estrutura de mola mola-contexto <!--o couchbase cache artefato nós construído anterior--> com.couchbase.cliente couchbase-mola-cache 1.0-FOTOGRAFIA org.estrutura de mola.inicialização mola-inicialização-mentor-plug-in |
Adicionar entidade e repositório de gerenciamento de livros
Usaremos o exemplo de um Livro
(conforme encontrado no repositório "COMEÇANDO - Armazenamento de dados em cache com o Spring" guia oficial do Spring.io).
Criar o Livro
classe de entidade em src/main/java/com/couchbase/demo/Book.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 |
importação java.io.Serializável; público classe Livro implementa Serializável { privado estático final longo serialVersionUID = -7674163614777124381L; privado Cordas isbn; privado Cordas título; público Livro(Cordas isbn, Cordas título) { este.isbn = isbn; este.título = título; } público Cordas getIsbn() { retorno isbn; } público vazio setIsbn(Cordas isbn) { este.isbn = isbn; } público Cordas getTitle() { retorno título; } público vazio setTitle(Cordas título) { este.título = título; } @Substituir público Cordas toString() { retorno "Livro{" + "isbn='" + isbn + ''' + ", title='" + título + ''' + '}'; } } |
Observe o
Livro
classe éSerializável
Por enquanto, isso é importante para o armazenamento do Couchbase.
Crie uma interface de repositório simples e uma implementação ingênua que simule um atraso:
em src/main/java/com/couchbase/demo/BookRepository.java
:
1 2 3 4 5 6 7 |
pacote com.couchbase.demonstração; público interface BookRepository { Livro getByIsbn(Cordas isbn); } |
em 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 |
pacote com.couchbase.demonstração; importação org.slf4j.Registrador; importação org.slf4j.Fábrica de registradores; importação org.estrutura de mola.estereótipo.Componente; @Componente público classe SimpleBookRepository implementa BookRepository { privado estático final Registrador registro = Fábrica de registradores.getLogger(SimpleBookRepository.classe); @Substituir público Livro getByIsbn(Cordas isbn) { simularSlowService(); Livro resultado = novo Livro(isbn, "Algum livro"); registro.informações("Busca real de " + isbn); retorno resultado; } // Não faça isso em casa privado vazio simularSlowService() { tentar { longo tempo = 5000L; Tópico.dormir(tempo); } captura (InterruptedException e) { lançar novo IllegalStateException(e); } } } |
O principal Inicialização do Spring
Aplicativo
Por fim, crie um aplicativo que use o repositório em 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 |
pacote com.couchbase.demonstração; importação org.slf4j.Registrador; importação org.slf4j.Fábrica de registradores; importação org.estrutura de mola.feijões.fábrica.anotação.Com fio automático; importação org.estrutura de mola.inicialização.CommandLineRunner; importação org.estrutura de mola.inicialização.SpringApplication; importação org.estrutura de mola.inicialização.autoconfigurar.SpringBootApplication; importação org.estrutura de mola.estereótipo.Componente; @SpringBootApplication público classe Aplicativo { privado estático final Registrador registro = Fábrica de registradores.getLogger(Aplicativo.classe); @Componente estático classe Corredor implementa CommandLineRunner { @Com fio automático privado BookRepository bookRepository; @Substituir público vazio executar(Cordas... argumentos) lançamentos Exceção { longo iniciar; registro.informações(".... Buscando livros"); fetchAndLog("isbn-1234"); fetchAndLog("isbn-1234"); fetchAndLog("isbn-1234"); fetchAndLog("isbn-8888"); fetchAndLog("isbn-8888"); } privado vazio fetchAndLog(Cordas isbn) { longo iniciar = Sistema.currentTimeMillis(); Livro livro = bookRepository.getByIsbn(isbn); longo tempo = Sistema.currentTimeMillis() - iniciar; registro.informações(isbn + " --> " + livro + " em " + tempo + "ms"); } } público estático vazio principal(Cordas[] argumentos) { SpringApplication.executar(Aplicativo.classe, argumentos); } } |
Se você executar o Aplicativo
's principal
em seu IDE (ou se você invocar o método "mvn spring-boot:run
" na linha de comando), você perceberá que todas as chamadas são de fato muito lentas:
1 2 3 4 5 6 7 8 9 10 11 |
[...] .... Buscando livros [...] Real buscar de isbn-1234 [...] isbn-1234 --> Livro{isbn='isbn-1234', título="Algum livro} em 5001ms [...] Real buscar de isbn-1234 [...] isbn-1234 --> Livro{isbn='isbn-1234', título="Algum livro} em 5004ms [...] Real buscar de isbn-1234 [...] isbn-1234 --> Livro{isbn='isbn-1234', título="Algum livro} em 5004ms [...] Real buscar de isbn-8888 [...] isbn-8888 --> Livro{isbn='isbn-8888', título="Algum livro} em 5003ms [...] Real buscar de isbn-8888 [...] isbn-8888 --> Livro{isbn='isbn-8888', título="Algum livro} em 5003ms |
Adição de recursos de cache do Spring Boot
Para ativar o armazenamento em cache, você deve seguir algumas etapas: primeiro, você deve oferecer ao Spring um Gerenciador de cache
@Bean
…
Como estaremos usando o CouchbaseCacheManager
(é claro), precisaremos nos conectar a um Aglomerado
e usar um Balde
(a unidade de armazenamento onde o couchbase armazenará os documentos do cache).
Portanto, o CouchbaseCacheManager
precisa de um mapeamento entre Cache
e os correspondentes nomes Balde
para usar, passado como um Mapa
.
Em src/main/java/com/couchbase/demo/Application.java
adicione as seguintes declarações 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 Cordas CAIXA DE LIVROS = "livros"; @Feijão(destroyMethod = "desconectar") público Aglomerado agrupamento() { //isso se conecta a uma instância do Couchbase em execução no localhost retorno CouchbaseCluster.criar(); } @Feijão(destroyMethod = "fechar") público Balde balde() { //esse será o bucket onde todos os dados relacionados ao cache serão armazenados //observe que o bucket "default" deve existir retorno agrupamento().openBucket("default", ""); } @Feijão público Gerenciador de cache gerenciador de cache() { Mapa<Cordas, Balde> mapeamento = novo HashMap<Cordas, Balde>(); //faremos com que esse gerenciador de cache reconheça um único cache chamado "books" mapeamento.colocar(CAIXA DE LIVROS, balde()); retorno novo CouchbaseCacheManager(mapeamento); } |
Em seguida, você deseja ativar a varredura de anotações relacionadas ao cache e o proxy associado, colocando a opção @EnableCaching
na anotação Aplicativo
classe.
Ativar o cache em SimpleBookRepository
Vamos ver como ativar o cache real em nosso SimpleBookRepository
e verifique como o aplicativo se comporta depois disso.
Para fazer getByIsbn
automaticamente no cache na primeira chamada e servir as chamadas subsequentes com dados do cache, basta anotá-lo dessa forma:
1 2 3 4 5 6 7 8 |
@Substituir @Armazenável em cache(Aplicativo.CAIXA DE LIVROS) //usando o nome do cache que declaramos anteriormente público Livro getByIsbn(Cordas isbn) { simularSlowService(); Livro resultado = novo Livro(isbn, "Algum livro"); registro.informações("Busca real de " + isbn); retorno resultado; } |
Vamos executar o aplicativo novamente e ver como ele se comporta agora:
1 2 3 4 5 6 7 8 |
[...] .... Buscando livros [...] Real buscar de isbn-1234 [...] isbn-1234 --> Livro{isbn='isbn-1234', título="Algum livro} em 5022ms [...] isbn-1234 --> Livro{isbn='isbn-1234', título="Algum livro} em 3ms [...] isbn-1234 --> Livro{isbn='isbn-1234', título="Algum livro} em 1ms [...] Real buscar de isbn-8888 [...] isbn-8888 --> Livro{isbn='isbn-8888', título="Algum livro} em 5007ms [...] isbn-8888 --> Livro{isbn='isbn-8888', título="Algum livro} em 1ms |
Uau! Isso é muito melhor para invocações após a primeira, parece que está de fato em cache :-)
Como ver os dados no Couchbase
Vamos dar uma olhada rápida no console da Web para verificar se esses ótimos tempos podem ser atribuídos ao Couchbase:
- abra uma nova guia em seu navegador e navegue até
http://localhost:8091
. - Conecte-se ao console da Web.
- ir para o
Compartimentos de dados
e clique na guiaDocumentos
para o balde que você escolheu usar ("padrão").
O que você vê nessa tela (link rápido para os preguiçosos) deve ser semelhante a este:
Podemos ver que ambos os livros foram armazenados em cache no couchbase, usando o cache:CACHE_NAME:CACHE_KEY
para os IDs de documentos.
Conclusão
O armazenamento em cache fácil usando o Couchbase agora está ao seu alcance!
Há muito mais que Spring Cache
pode fazer por você (por exemplo, escolher como criar a chave de cache, cache condicional, despejo de cache, etc.), e há especificidades para couchbase-spring-cache
(por exemplo, para a limpeza do cache, você pode escolher entre usar uma exibição que removerá apenas o documento relevante ou, se o seu bucket for dedicado a um único cache, use o descarga
mecanismo...).
Espero que este tutorial introdutório tenha despertado seu apetite para usar o cache facilmente usando Spring Cache
e Couchbase
!
As próximas etapas provavelmente serão a introdução de formatos de armazenamento alternativos (como JSON) e a oferta do artefato no Maven Central ou em um repositório Maven semelhante publicamente acessível (Bintray alguém?)...
Fique atento às notícias relacionadas à primavera em um futuro próximo!
Enquanto isso, boa codificação :)