Redis com Spring Boot na Prática Passo a Passo

Compartilhar:

O Redis, abreviação para Remote Directory Server, é um sistema de armazenamento remoto de estrutura de dados em memória, sendo um banco de dados de código aberto licenciado sob BSD. Destaca-se por seu alto desempenho, replicação e um modelo de dados exclusivo.

Redis oferece uma variedade de estruturas de dados, como strings, hashes, listas, conjuntos, conjuntos classificados com consultas de intervalo, bitmaps, hiperloglogs, índices geoespaciais e fluxos.

Compatível com a maioria das linguagens de programação, o Redis é escrito em ANSI C e é funcional em diversos sistemas POSIX, como Linux e OS X, sem necessidade de dependências externas.

Hoje, você vai aprender a como integrar o Redis em uma aplicação Spring Boot, ao final vamos realizar um teste de desempenho em uma Api com o Postman, acompanhe até o final e melhore o desempenhos dos seus projetos em Java.

redis spring boot

Integrando o Redis com Spring Boot

Vamos criar um tutorial detalhado, passo a passo, sobre como integrar o Redis com o Spring Boot. Neste tutorial, iremos utilizar o banco de dados Postgres e testar nossa API utilizando o Postman.

Configuração do Ambiente

Em primeiro momento, precisamos baixar o redis em seu ambiente de de desenvolvimento, caso você preferir baixar uma imagem no docker, segue abaixo as comandos:

docker pull redis/redis-stack-server:latest

Depois de baixar a imagem, você pode iniciar um contêiner Redis com o seguinte comando. Se a imagem ainda não estiver baixada, o comando cuidará disso, criando o contêiner ao mesmo tempo.

Agora, você tem a flexibilidade de definir o mapeamento da porta do servidor para uma porta diferente. Basta substituir “6379:6379” pela porta desejada, seguindo o formato “MY_PORT:6379”:

docker run -d --name redis-stack-server -p 6379:6379 redis/redis-stack-server:latest

Configuração do Spring Boot

Crie um projeto Spring Boot, em nosso exemplo vamos utilizar a versão 17 do Java e versão superior a 3.x.x do Spring, porém você pode utilizar qualquer outra versão.

Repositório do projeto no GitHub: GuilhermeJWT/redis-spring-boot.

Adicione a seguinte dependência do Redis no arquivo pom.xml:

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis</artifactId>
		</dependency>

Agora precisamos habilitar a configuração de cache no projeto, na classe Principal do Spring Boot, adicione a seguinte anotação:

package br.com.virandoprogramador.redis_spring_boot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

@EnableCaching
@SpringBootApplication
public class RedisSpringBootApplication {

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

A anotação @EnableCaching é uma configuração do Spring Boot que facilita a implementação de cache em aplicações. Ao ser adicionada a uma classe de configuração ou à classe principal da aplicação, essa anotação habilita o suporte a caching no contexto do Spring.

Uma vez ativado, o Spring Boot gerencia o cache para métodos anotados com @Cacheable, @CachePut e @CacheEvict. Essas anotações permitem definir o comportamento de caching para métodos específicos, melhorando o desempenho da aplicação, especialmente em operações que envolvem acesso a banco de dados, chamadas de API externas ou outros processos.

Configurando o arquivo application.properties

No seu arquivo application.properties, adicione as seguintes configurações:

spring.cache.type=redis
spring.cache.redis.cache-null-values=true
spring.data.redis.host=localhost
spring.data.redis.port=6379

Observação: note que configuramos o host e porta do servidor Redis, se você adicionou alguma senha para acessar, utilize a variavel spring.data.redis.password, em nosso exemplo não iremos utilizar.

Após esse passo, já temos nosso ambiente configurado com Redis, os próximos passos será a criação de uma api bem simples para teste.

package br.com.virandoprogramador.redis_spring_boot.service;

import br.com.virandoprogramador.redis_spring_boot.exception.UsuarioNaoEncontradoException;
import br.com.virandoprogramador.redis_spring_boot.model.ModelUsuario;
import br.com.virandoprogramador.redis_spring_boot.repository.UsuarioRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

@Service
public class UsuarioService {

    @Autowired
    private UsuarioRepository usuarioRepository;

    @Cacheable(value = "ModelUsuario")
    public List<ModelUsuario> listarUsuarios(){
        return usuarioRepository.findAll();
    }

    @Cacheable(value = "ModelUsuario", key = "#id")
    public ModelUsuario pesquisaPorId(Long id){
        Optional<ModelUsuario>  modelUsuario = usuarioRepository.findById(id);
        return modelUsuario.orElseThrow(() -> new UsuarioNaoEncontradoException("Usuario não encontrado"));
    }

    public ModelUsuario salvarUsuario(ModelUsuario modelUsuario){
        return usuarioRepository.save(modelUsuario);
    }

    @CachePut(value = "ModelUsuario", key = "#id")
    public ModelUsuario alterarUsuario(ModelUsuario modelUsuario, Long id){
        ModelUsuario usuarioAlterado = usuarioRepository.findById(id)
                .orElseThrow(() -> new UsuarioNaoEncontradoException("Usuario não encontrado"));

        usuarioAlterado.setNome(modelUsuario.getNome());
        usuarioAlterado.setEmail(modelUsuario.getEmail());
        return usuarioRepository.save(usuarioAlterado);
    }

    @CacheEvict(value = "ModelUsuario", key = "#id")
    public void deletarUsuario(Long id){
        ModelUsuario modelUsuario = usuarioRepository.findById(id)
                .orElseThrow(() -> new UsuarioNaoEncontradoException("Usuario não encontrado"));
        usuarioRepository.deleteById(modelUsuario.getId());
    }
}

Explicando as Anotações do Redis

Abaixo, irei detalhar como cada anotação está sendo utilizada no projeto, ao final vamos testar cada uma delas no Postman, e você ira ver o resultado.

Anotação @Cacheable

@Cacheable(value = "ModelUsuario")
    public List<ModelUsuario> listarUsuarios(){
        return usuarioRepository.findAll();
    }

Ao adicionar a anotação @Cacheable a um método que recupera a lista de usuários do banco de dados, o Spring Boot armazena em cache o resultado da chamada desse método.

Isso significa que, quando o método é chamado pela primeira vez, os dados são recuperados do banco de dados e armazenados em cache. Nas chamadas subsequentes ao mesmo método com os mesmos parâmetros, o Spring Boot recupera os dados diretamente do cache, evitando a necessidade de acessar o banco de dados novamente.

Anotação @CachePut

@CachePut(value = "ModelUsuario", key = "#id")
    public ModelUsuario alterarUsuario(ModelUsuario modelUsuario, Long id){
        ModelUsuario usuarioAlterado = usuarioRepository.findById(id)
                .orElseThrow(() -> new UsuarioNaoEncontradoException("Usuario não encontrado"));

        usuarioAlterado.setNome(modelUsuario.getNome());
        usuarioAlterado.setEmail(modelUsuario.getEmail());
        return usuarioRepository.save(usuarioAlterado);
    }

Quando um método marcado com @CachePut é invocado, o Spring Boot executa o método e, em seguida, atualiza o cache com o resultado retornado pelo método.

Isso significa que, sempre que um usuário é alterado no banco de dados, o cache correspondente é atualizado com os novos dados.

Ao configurar a chave de cache com key=”#id”, você está indicando ao Spring Boot que o cache deve ser atualizado ou invalidado com base no ID do usuário que está sendo alterado. Isso garante que apenas o cache relacionado a esse usuário específico seja afetado pela alteração, mantendo os outros dados do cache intactos.

Anotação @CacheEvict

@CacheEvict(value = "ModelUsuario", key = "#id")
    public void deletarUsuario(Long id){
        ModelUsuario modelUsuario = usuarioRepository.findById(id)
                .orElseThrow(() -> new UsuarioNaoEncontradoException("Usuario não encontrado"));
        usuarioRepository.deleteById(modelUsuario.getId());
    }

Ao marcar um método com @CacheEvict, o Spring Boot identifica e remove as entradas relacionadas ao método especificado do cache. Isso é especialmente útil em operações de exclusão, onde é importante garantir que o cache seja atualizado corretamente após a remoção dos dados.

Ao configurar a chave de cache com key=”#id”, você diz para o Spring Boot a invalidar apenas o cache associado ao usuário que está sendo excluído. Isso garante que apenas os dados do cache relacionados a esse usuário específico sejam removidos, preservando as outras entradas do cache.

Testando o Cache no Postman

Agora vamos testar! você vai ver o resultado de aplicar Caches em suas aplicações.

Antes de ver o desempenho do cache, vamos criar uma Api com algumas rotas que serão chamadas pela camada UsuarioService, onde estão os métodos anotados com o Redis.

Classe: UsuarioController

package br.com.virandoprogramador.redis_spring_boot.controller;

import br.com.virandoprogramador.redis_spring_boot.model.ModelUsuario;
import br.com.virandoprogramador.redis_spring_boot.service.UsuarioService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("api/usuario")
public class UsuarioController {

    @Autowired
    private UsuarioService usuarioService;

    @GetMapping("/listar")
    public ResponseEntity<List<ModelUsuario>> listarUsuario(){
        return ResponseEntity.ok().body(usuarioService.listarUsuarios());
    }

    @GetMapping("/pesquisar/{id}")
    public ModelUsuario pesquisarUsuario(@PathVariable Long id){
        return usuarioService.pesquisaPorId(id);
    }

    @PostMapping("/salvar")
    public ResponseEntity<ModelUsuario> salvarUsuario(@RequestBody ModelUsuario modelUsuario){
        return ResponseEntity.ok(usuarioService.salvarUsuario(modelUsuario));
    }

    @PutMapping("/alterar/{id}")
    public ResponseEntity<ModelUsuario> alterarUsuario(@RequestBody ModelUsuario modelUsuario, @PathVariable Long id){
        return ResponseEntity.ok(usuarioService.alterarUsuario(modelUsuario, id));
    }

    @DeleteMapping("/deletar/{id}")
    public void deletarUsuario(@PathVariable Long id){
        usuarioService.deletarUsuario(id);
    }
}

No Postman, acesse as seguintes rotas:

  • localhost:8080/api/usuario/salvar
  • localhost:8080/api/usuario/alterar/1
  • localhost:8080/api/usuario/listar
  • localhost:8080/api/usuario/pesquisar/1
  • localhost:8080/api/usuario/deletar/1

Salve alguns dados na api de salvar, nós vamos testar o métodos listar todos e verificar o desempenho utilizando cache.

Api de Listar Usuários:

Observação: note que a primeira consulta na api de listar Usuários, levou 1034 milissegundos para retornar os dados do banco de dados.

A segunda consulta deve retornar em um tempo muito menor utilizando o cache:

Observação: note que na segunda consulta, o tempo de resposta do servidor foi de apenas 22 milissegundos, os dados foram armazenados em cache na primeira consulta, logo na segunda a aplicação não precisa consultar o banco de dados para recuperar esses dados. Agora basta testar o cache nos outros endpoints =).

Conclusão sobre Caches com Redis e Spring Boot

Desenvolvemos uma API REST utilizando Spring Boot e Redis para armazenar e gerenciar os dados dos usuários. Durante os testes de desempenho, observamos uma melhoria significativa no tempo de resposta ao utilizar o cache do Redis.

Ao listar os usuários pela primeira vez, a consulta levou 1034 milissegundos para ser concluída. No entanto, após o resultado ser armazenado em cache pelo Redis, a segunda consulta teve seu tempo de execução drasticamente reduzido para apenas 22 milissegundos.

Essa diferença de desempenho evidencia os benefícios do caching em operações repetidas, onde o Redis permite armazenar e recuperar dados rapidamente, minimizando a necessidade de acessar o banco de dados repetidamente.

Perguntas Frequentes

O que é Redis e para que serve?

O Redis é um armazenamento remoto de estrutura de dados na memória, caracterizado por sua eficiência e desempenho. Pode ser utilizado de várias maneiras, oferecendo soluções em diferentes contextos:

Banco de Dados na Memória:

O Redis pode ser empregado como um banco de dados na memória, proporcionando um espaço eficiente para armazenamento e recuperação de dados. Sua natureza No-SQL elimina a necessidade de tabelas, sequências ou junções, permitindo o armazenamento de dados em diversos formatos, como strings, hashes, listas e conjuntos.

Esse modelo simplificado é acompanhado de serviços integrados, tornando-o uma opção viável para muitas aplicações.

Cache:

Uma das utilizações mais comuns do Redis é como um sistema de cache para aumentar o desempenho de aplicativos. Ao armazenar dados em memória, o Redis reduz a necessidade de consultas repetidas ao banco de dados, agilizando o acesso a informações frequentemente acessadas.

Isso é especialmente benéfico em cenários onde a resposta rápida é essencial, como em aplicativos web e móveis.

Message Broker (MQ):

Redis pode funcionar como um Message Broker, facilitando a comunicação assíncrona entre diferentes componentes de um sistema distribuído.

Ele oferece suporte a diferentes padrões de mensagens, como pub/sub (publicar/inscrever-se), filas de mensagens e filas de tópicos, tornando-o uma escolha popular para sistemas de mensageria em tempo real.

Como acessar o Redis?

Para acessar o Redis, a ferramenta mais comum é o redis-cli, uma interface de linha de comando que permite interagir diretamente com o Redis a partir do terminal. Com o redis-cli, os usuários têm maior liberdade na leitura e manipulação dos dados armazenados no Redis.

Outro ponto bem legal, é possível enviar instruções administrativas para o Redis usando o console, o que pode ser útil para fins de automação de scripts ou para realizar tarefas de manutenção e gerenciamento do banco de dados.

Qual a vantagem de usar Redis Cache em sua aplicação?

Usar Redis Cache em sua aplicação oferece uma série de vantagens. Em primeiro lugar, o Redis é extremamente rápido e eficiente, o que significa que pode armazenar e recuperar dados em tempo recorde, reduzindo significativamente o tempo de resposta da sua aplicação.

O Redis também é altamente escalável e robusto, capaz de lidar com grandes volumes de dados e cargas de trabalho intensas sem comprometer o desempenho.

5/5 - (1 vote)
Compartilhar:

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *