Introdução ao nosso amigo cache.
Fala galera, eu de volta aqui. Hoje vou começar a falar sobre cache, mas este é o primeiro artigo de dois que irei lançar para falar deste tema. Vamos ver aqui o start do tema e a aplicação local utilizando spring boot, entender as anotações básicas e seu conceito. Em um segundo artigo vamos falar de cache distrubuído e sua aplicabilidade, além de configurações relevantes do cache. Agora, bora falar de cache.
O que é e qual a finalidade do cache na prática para APIs ?
Eu defino cache como: Uma técnica de memorização inteligente de alocação e recuperação de dados.
O que é isso ? De forma simples, os dados de consultas custosas são armzenados de forma que possam ser recuperados com um custo menor que o de suas consultas originais.
Qual a finalidade disso ? Garantir uma melhor performance, que em muitos cenários é um gargalo nas aplicações.
Você pode utilizar cache local ou distribuido (com redis por exemplo, vou falar sobre isso no próximo artigo), ambos são úteis e tem suas finalidades e aplicações para cada cenário e arquitetura adotada. Agora vou apresentar o uso de cache local com spring boot de forma simples e disponibilizo aqui um projeto exemplo que pode te ajudar a entender melhor.
O spring boot prove um conjunto de recursos para implementar cache. Para começar precisamos anotar a aplicação habilitando o cache.
@SpringBootApplication
@EnableCaching
public class CachectmaitApplication {
public static void main(String[] args) {
SpringApplication.run(CachectmaitApplication.class, args);
}
}
Agora vamos ver as anotações que podemos usar para cachear o que faz sentido na aplicação e como atualizar e remover este cache com as anotações.
@Cacheable
Essa anotação cria o cache e podemos atribuir a ele nome e chave, como podemos ver abaixo:
@SneakyThrows
@Cacheable(cacheNames = “Pessoas”, key = “#root.method.name” )
public List<PessoaResponseDTO> getAll(){
Thread.sleep(2000L);
return pessoaRepository.findAll()
.stream()
.map(pessoaResponseConverter::convert)
.collect(Collectors.toList());
}
Após isso, quando chamar getAll será acionado o repositório, depois as próximas requisições o cache será acionado, até que o cache seja inválido por alguma configuração (vamos falar mais sobre isso no próximo artigo mas nesse ainda falaremos um pouco mais a frente). Após a primeira requisição será alocado um espaço em memória, o identificador “Pessoas::getAll” (configuração cacheNames + key) para armazenar todos os registros retornados na consulta. Podemos consultar por chave única, assim configuramos o cache para armazenar esses registros. A configuração é a mesma mudando que a chave do cache é dinâmica, ou seja, para cada identificador da Pessoa será criado/alocado os dados, veja abaixo:
@SneakyThrows
@Cacheable(cacheNames = “Pessoa”, key = “#uuid” )
public PessoaResponseDTO getPessoaByUuid(final String uuid) {
Thread.sleep(2000L);
return pessoaResponseConverter.convert(getByUuid(uuid));
}
@CachePut e @CacheEvict
Os dados foram armazenados em cache, mas os dados são mutáveis, então precisamos atualizar ou descartar essas dados em cache, para que assim a aplicação possa recuperar os novos dados e atualizar/rearmazenar. É importante frizar que esta etapa é fundamental para que o cache não produza falsos dados reais, por isso mapear devidamente é muito importante. Abaixo vemos o exemplo:
@CachePut(cacheNames = “Pessoa”, key=”#request.getUuid()”)
@CacheEvict(cacheNames = “Pessoas”, allEntries = true)
public PessoaResponseDTO put(final PessoaRequestPutDTO request) {
return pessoaRepository.getByUuid(request.getUuid())
.map(pessoa -> pessoaRequestConverter.convert(request, pessoa))
.map(pessoaRepository::save)
.map(pessoaResponseConverter::convert)
.orElseThrow(this::generateNotFound);
}
Como o nome já sugere, o @Cacheput atualiza o cache. (Obs: Poucas pessoas falam isso, mas saiba que caso você atualize um dado que não está em cache, ele irá criar o cache do dado atualizado.) Já o @CacheEvict remove o cache armazenado e caso não exista não se preocupe que isso é tratado internamente.
Existem muitos detalhes relevantes e propriedades importantes das anatoções que fazem do trabalho com cache algo delicado e que pode dar muitas dores de cabeças. Para ver um pouco mais na prática sugiro baixar o projeto exemplo e dar uma olhada. Além disso, em breve lanço o segundo artigo desta série falando de cache distribuído com spring boot e redis, nele vou abordar as configurações básicas e importantes para sua aplicação. Pode adquirir mais referências aqui.
Antes de ir mais uma coisinha: Nunca se esqueça que cache é bom mas a diferença entre veneno e antídoto é a dose.
É isso e nos falamos em breve no segundo artigo da série. vlw flw ! :D
Originally published at https://www.linkedin.com.